diff --git a/visualvm/libs.profiler/lib.profiler/src/org/graalvm/visualvm/lib/jfluid/heap/HeapFactory.java b/visualvm/libs.profiler/lib.profiler/src/org/graalvm/visualvm/lib/jfluid/heap/HeapFactory.java index 3deac82653..2f3f9df867 100644 --- a/visualvm/libs.profiler/lib.profiler/src/org/graalvm/visualvm/lib/jfluid/heap/HeapFactory.java +++ b/visualvm/libs.profiler/lib.profiler/src/org/graalvm/visualvm/lib/jfluid/heap/HeapFactory.java @@ -32,6 +32,7 @@ import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; +import java.nio.ByteBuffer; /** @@ -87,6 +88,22 @@ public static Heap createHeap(File heapDump, int segment) return new HprofHeap(heapDump, segment, cacheDir); } + + /** Factory method for processing heap dumps in memory. When heap data + * aren't available on disk, but only in memory, create a {@link ByteBuffer} + * from them and use this factory method to create their {@link Heap} + * representation. + * + * @param buffer data representing the heap dump + * @param segment select corresponding dump from multi-dump file + * @return implementation of {@link Heap} corresponding to the memory dump + * passed in the {@code buffer} parameter + * @throws IOException if the access to the buffer fails or data are corrupted + * @since 2.2 + */ + public static Heap createHeap(ByteBuffer buffer, int segment) throws IOException { + return new HprofHeap(buffer, segment, new CacheDirectory(null)); + } static Heap loadHeap(CacheDirectory cacheDir) throws FileNotFoundException, IOException { diff --git a/visualvm/libs.profiler/lib.profiler/src/org/graalvm/visualvm/lib/jfluid/heap/HprofByteBuffer.java b/visualvm/libs.profiler/lib.profiler/src/org/graalvm/visualvm/lib/jfluid/heap/HprofByteBuffer.java index 5c7b50d419..b949c021d4 100644 --- a/visualvm/libs.profiler/lib.profiler/src/org/graalvm/visualvm/lib/jfluid/heap/HprofByteBuffer.java +++ b/visualvm/libs.profiler/lib.profiler/src/org/graalvm/visualvm/lib/jfluid/heap/HprofByteBuffer.java @@ -27,6 +27,7 @@ import java.io.File; import java.io.IOException; +import java.nio.ByteBuffer; import java.util.Date; import java.util.ResourceBundle; @@ -84,6 +85,10 @@ static HprofByteBuffer createHprofByteBuffer(File dumpFile) } } + static HprofByteBuffer createHprofByteBuffer(ByteBuffer bb) throws IOException { + return new HprofMappedByteBuffer(bb); + } + abstract char getChar(long index); abstract double getDouble(long index); diff --git a/visualvm/libs.profiler/lib.profiler/src/org/graalvm/visualvm/lib/jfluid/heap/HprofHeap.java b/visualvm/libs.profiler/lib.profiler/src/org/graalvm/visualvm/lib/jfluid/heap/HprofHeap.java index 1de494b878..6614e0a59a 100644 --- a/visualvm/libs.profiler/lib.profiler/src/org/graalvm/visualvm/lib/jfluid/heap/HprofHeap.java +++ b/visualvm/libs.profiler/lib.profiler/src/org/graalvm/visualvm/lib/jfluid/heap/HprofHeap.java @@ -32,6 +32,7 @@ import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; +import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -128,11 +129,11 @@ class HprofHeap implements Heap { private boolean retainedSizeByClassComputed; private final Object retainedSizeByClassLock = new Object(); private int idMapSize; - private int segment; + private final int segment; // for serialization - File heapDumpFile; - CacheDirectory cacheDirectory; + final File heapDumpFile; + final CacheDirectory cacheDirectory; //~ Constructors ------------------------------------------------------------------------------------------------------------- @@ -153,6 +154,23 @@ class HprofHeap implements Heap { heapDumpFile = dumpFile; } + HprofHeap(ByteBuffer bb, int seg, CacheDirectory cacheDir) throws IOException { + cacheDirectory = cacheDir; + dumpBuffer = HprofByteBuffer.createHprofByteBuffer(bb); + segment = seg; + fillTagBounds(dumpBuffer.getHeaderSize()); + heapDumpSegment = computeHeapDumpStart(); + + if (heapDumpSegment != null) { + fillHeapTagBounds(); + } + + idToOffsetMap = new LongMap(idMapSize,dumpBuffer.getIDSize(),dumpBuffer.getFoffsetSize(), cacheDirectory); + nearestGCRoot = new NearestGCRoot(this); + gcRoots = new HprofGCRoots(this); + heapDumpFile = null; + } + //~ Methods ------------------------------------------------------------------------------------------------------------------ public List getAllClasses() { diff --git a/visualvm/libs.profiler/lib.profiler/src/org/graalvm/visualvm/lib/jfluid/heap/HprofMappedByteBuffer.java b/visualvm/libs.profiler/lib.profiler/src/org/graalvm/visualvm/lib/jfluid/heap/HprofMappedByteBuffer.java index f41fd7ac41..8d09aee39c 100644 --- a/visualvm/libs.profiler/lib.profiler/src/org/graalvm/visualvm/lib/jfluid/heap/HprofMappedByteBuffer.java +++ b/visualvm/libs.profiler/lib.profiler/src/org/graalvm/visualvm/lib/jfluid/heap/HprofMappedByteBuffer.java @@ -27,7 +27,9 @@ import java.io.File; import java.io.FileInputStream; +import java.io.FileNotFoundException; import java.io.IOException; +import java.nio.ByteBuffer; import java.nio.MappedByteBuffer; import java.nio.channels.FileChannel; @@ -39,16 +41,17 @@ class HprofMappedByteBuffer extends HprofByteBuffer { //~ Instance fields ---------------------------------------------------------------------------------------------------------- - private MappedByteBuffer dumpBuffer; + private final ByteBuffer dumpBuffer; //~ Constructors ------------------------------------------------------------------------------------------------------------- HprofMappedByteBuffer(File dumpFile) throws IOException { - FileInputStream fis = new FileInputStream(dumpFile); - FileChannel channel = fis.getChannel(); - length = channel.size(); - dumpBuffer = channel.map(FileChannel.MapMode.READ_ONLY, 0, length); - channel.close(); + this(mmap(dumpFile)); + } + + HprofMappedByteBuffer(ByteBuffer buffer) throws IOException { + this.dumpBuffer = buffer; + this.length = buffer.capacity(); readHeader(); } @@ -87,4 +90,12 @@ synchronized void get(long position, byte[] chars) { dumpBuffer.position((int) position); dumpBuffer.get(chars); } + + private static MappedByteBuffer mmap(File dumpFile) throws IOException, FileNotFoundException { + FileInputStream fis = new FileInputStream(dumpFile); + FileChannel channel = fis.getChannel(); + MappedByteBuffer d = channel.map(FileChannel.MapMode.READ_ONLY, 0, channel.size()); + channel.close(); + return d; + } } diff --git a/visualvm/libs.profiler/lib.profiler/test/unit/src/org/graalvm/visualvm/lib/jfluid/heap/HeapFromBufferTest.java b/visualvm/libs.profiler/lib.profiler/test/unit/src/org/graalvm/visualvm/lib/jfluid/heap/HeapFromBufferTest.java new file mode 100644 index 0000000000..6ad210013a --- /dev/null +++ b/visualvm/libs.profiler/lib.profiler/test/unit/src/org/graalvm/visualvm/lib/jfluid/heap/HeapFromBufferTest.java @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2010, 2021, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package org.graalvm.visualvm.lib.jfluid.heap; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.net.URISyntaxException; +import java.net.URL; +import java.nio.ByteBuffer; +import java.nio.channels.FileChannel; +import org.junit.Before; + +public class HeapFromBufferTest extends HeapTest { + public HeapFromBufferTest() { + } + + @Before + public void setUp() throws IOException, URISyntaxException { + URL url = getClass().getResource("small_heap.bin"); + File heapFile = new File(url.toURI()); + ByteBuffer buffer = ByteBuffer.allocate((int) heapFile.length()); + try (FileChannel ch = new FileInputStream(heapFile).getChannel()) { + while (buffer.remaining() > 0) { + int len = ch.read(buffer); + if (len == -1) { + break; + } + } + } + heap = HeapFactory.createHeap(buffer, 0); + } + +} diff --git a/visualvm/libs.profiler/lib.profiler/test/unit/src/org/graalvm/visualvm/lib/jfluid/heap/HeapTest.java b/visualvm/libs.profiler/lib.profiler/test/unit/src/org/graalvm/visualvm/lib/jfluid/heap/HeapTest.java index d3d29ad98d..c8fc008624 100644 --- a/visualvm/libs.profiler/lib.profiler/test/unit/src/org/graalvm/visualvm/lib/jfluid/heap/HeapTest.java +++ b/visualvm/libs.profiler/lib.profiler/test/unit/src/org/graalvm/visualvm/lib/jfluid/heap/HeapTest.java @@ -48,9 +48,7 @@ import java.util.Properties; import java.util.TimeZone; import org.junit.After; -import org.junit.AfterClass; import org.junit.Before; -import org.junit.BeforeClass; import org.junit.Test; import static org.junit.Assert.*; @@ -59,19 +57,11 @@ * @author Tomas Hurka */ public class HeapTest { - private Heap heap; + Heap heap; public HeapTest() { } - @BeforeClass - public static void setUpClass() throws Exception { - } - - @AfterClass - public static void tearDownClass() throws Exception { - } - @Before public void setUp() throws IOException, URISyntaxException { URL url = getClass().getResource("small_heap.bin");