Skip to content

Commit 56e35ab

Browse files
committed
GH-599 handle instances with a deep path to the GC root in the correct order
1 parent c4194f5 commit 56e35ab

File tree

3 files changed

+70
-4
lines changed

3 files changed

+70
-4
lines changed

visualvm/libs.profiler/lib.profiler.heap/src/org/graalvm/visualvm/lib/jfluid/heap/HprofHeap.java

Lines changed: 44 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ class HprofHeap implements Heap {
103103
private static final boolean DEBUG = false;
104104

105105
private static final String SNAPSHOT_ID = "NBPHD";
106-
private static final int SNAPSHOT_VERSION = 4;
106+
private static final int SNAPSHOT_VERSION = 5;
107107
private static final String OS_PROP = "os.name";
108108

109109
//~ Instance fields ----------------------------------------------------------------------------------------------------------
@@ -728,6 +728,41 @@ void computeRetainedSize() {
728728
new TreeObject(this,leaves).computeTrees();
729729
domTree = new DominatorTree(this,nearestGCRoot.getMultipleParents());
730730
domTree.computeDominators();
731+
732+
// deep path first
733+
try {
734+
LongBuffer deepPathBuffer = nearestGCRoot.getDeepPathBuffer();
735+
LongBuffer deepPath = deepPathBuffer.revertBuffer();
736+
737+
deepPathBuffer.reset();
738+
deepPathBuffer.delete();
739+
if (deepPath.hasData()) {
740+
for (long deepObjId = deepPath.readLong(); deepObjId != 0; deepObjId = deepPath.readLong()) {
741+
LongMap.Entry deepObjEntry = idToOffsetMap.get(deepObjId);
742+
assert deepObjEntry.isDeepObj();
743+
long idomId = domTree.getIdomId(deepObjId, deepObjEntry);
744+
LongMap.Entry idomEntry = idToOffsetMap.get(idomId);
745+
746+
if (!deepObjEntry.isTreeObj()) {
747+
Instance deepInstance = getInstanceByID(deepObjId);
748+
long size = deepInstance.getSize();
749+
long origSize = deepObjEntry.getRetainedSize();
750+
751+
if (origSize < 0) origSize = 0;
752+
deepObjEntry.setRetainedSize(origSize + size);
753+
}
754+
if (idomEntry.isDeepObj() && !idomEntry.isTreeObj()) {
755+
long origSize = idomEntry.getRetainedSize();
756+
if (origSize < 0) origSize = 0;
757+
idomEntry.setRetainedSize(origSize + deepObjEntry.getRetainedSize());
758+
}
759+
}
760+
}
761+
deepPath.delete();
762+
} catch (IOException ex) {
763+
throw new IllegalArgumentException(ex.getLocalizedMessage(), ex);
764+
}
765+
731766
long[] offset = new long[] { allInstanceDumpBounds.startOffset };
732767

733768
for (long counter=0; offset[0] < allInstanceDumpBounds.endOffset; counter++) {
@@ -748,9 +783,10 @@ void computeRetainedSize() {
748783
LongMap.Entry instanceEntry = idToOffsetMap.get(instanceId);
749784
long idom = domTree.getIdomId(instanceId,instanceEntry);
750785
boolean isTreeObj = instanceEntry.isTreeObj();
786+
boolean deepObj = instanceEntry.isDeepObj();
751787
long instSize = 0;
752788

753-
if (!isTreeObj && (instanceEntry.getNearestGCRootPointer() != 0 || gcRoots.getGCRoots(new Long(instanceId)) != null)) {
789+
if (!deepObj && !isTreeObj && (instanceEntry.getNearestGCRootPointer() != 0 || gcRoots.getGCRoots(new Long(instanceId)) != null)) {
754790
long origSize = instanceEntry.getRetainedSize();
755791
if (origSize < 0) origSize = 0;
756792
Instance instance = getInstanceByOffset(new long[] {start});
@@ -759,9 +795,13 @@ void computeRetainedSize() {
759795
}
760796
if (idom != 0) {
761797
long size;
762-
LongMap.Entry entry;
798+
LongMap.Entry entry = idToOffsetMap.get(idom);
763799

764-
if (isTreeObj) {
800+
if (entry.isDeepObj()) {
801+
continue;
802+
} else if (isTreeObj) {
803+
size = instanceEntry.getRetainedSize();
804+
} else if (deepObj) {
765805
size = instanceEntry.getRetainedSize();
766806
} else {
767807
assert instSize != 0;

visualvm/libs.profiler/lib.profiler.heap/src/org/graalvm/visualvm/lib/jfluid/heap/LongMap.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ class Entry extends AbstractLongMap.Entry {
5656
private static final byte NUMBER_LIST = 1;
5757
private static final byte GC_ROOT = 2;
5858
private static final byte TREE_OBJ = 4;
59+
private static final byte DEEP_OBJ = 8;
5960

6061
//~ Instance fields ------------------------------------------------------------------------------------------------------
6162

@@ -91,6 +92,15 @@ boolean isTreeObj() {
9192
return (getFlags() & TREE_OBJ) != 0;
9293
}
9394

95+
void setDeepObj() {
96+
byte flags = (byte)(getFlags() | DEEP_OBJ);
97+
setFlags(flags);
98+
}
99+
100+
boolean isDeepObj() {
101+
return (getFlags() & DEEP_OBJ) != 0;
102+
}
103+
94104
boolean hasOnlyOneReference() {
95105
return (getFlags() & NUMBER_LIST) == 0;
96106
}

visualvm/libs.profiler/lib.profiler.heap/src/org/graalvm/visualvm/lib/jfluid/heap/NearestGCRoot.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,19 +52,22 @@ class NearestGCRoot {
5252
private static final String SVM_REFFERENCE = "com.oracle.svm.core.heap.heapImpl.DiscoverableReference"; // NOI18N
5353
private static final String SVM_REFFERENCE_1 = "com.oracle.svm.core.heap.DiscoverableReference"; // NOI18N
5454
private static final String SVM_REFERENT_FIELD_NAME = "rawReferent"; // NOI18N
55+
private static final int DEEP_LEVEL = 10000;
5556

5657
//~ Instance fields ----------------------------------------------------------------------------------------------------------
5758

5859
private Field referentField;
5960
private HprofHeap heap;
6061
private LongBuffer readBuffer;
6162
private LongBuffer writeBuffer;
63+
private LongBuffer deepPathBuffer;
6264
private LongBuffer leaves;
6365
private LongBuffer multipleParents;
6466
private Set<JavaClass> referenceClasses;
6567
private boolean gcRootsComputed;
6668
private long allInstances;
6769
private long processedInstances;
70+
private long level;
6871
//private long leavesCount;
6972
//private long firstLevel;
7073
//private long multiParentsCount;
@@ -160,6 +163,7 @@ private boolean initSVMReference() {
160163

161164
private void computeOneLevel(Set<JavaClass> processedClasses) throws IOException {
162165
int idSize = heap.dumpBuffer.getIDSize();
166+
level++;
163167
for (;;) {
164168
Instance instance;
165169
long instanceOffset = readLong();
@@ -250,6 +254,7 @@ private void createBuffers() {
250254
writeBuffer = new LongBuffer(BUFFER_SIZE, heap.cacheDirectory);
251255
leaves = new LongBuffer(BUFFER_SIZE, heap.cacheDirectory);
252256
multipleParents = new LongBuffer(BUFFER_SIZE, heap.cacheDirectory);
257+
deepPathBuffer = new LongBuffer(BUFFER_SIZE, heap.cacheDirectory);
253258
}
254259

255260
private void deleteBuffers() {
@@ -309,6 +314,10 @@ private boolean writeConnection(long instanceId, long refInstanceId, boolean add
309314

310315
if (entry != null && entry.getNearestGCRootPointer() == 0L && heap.gcRoots.getGCRoots(refInstanceId) == null) {
311316
writeLong(entry.getOffset());
317+
if (level > DEEP_LEVEL) {
318+
deepPathBuffer.writeLong(refInstanceId);
319+
entry.setDeepObj();
320+
}
312321
if (addRefInstanceId) {
313322
if (!checkReferences(refInstanceId, instanceId)) {
314323
entry.addReference(instanceId);
@@ -379,12 +388,18 @@ LongBuffer getMultipleParents() {
379388
return multipleParents;
380389
}
381390

391+
LongBuffer getDeepPathBuffer() {
392+
computeGCRoots();
393+
return deepPathBuffer;
394+
}
395+
382396
//---- Serialization support
383397
void writeToStream(DataOutputStream out) throws IOException {
384398
out.writeBoolean(gcRootsComputed);
385399
if (gcRootsComputed) {
386400
leaves.writeToStream(out);
387401
multipleParents.writeToStream(out);
402+
deepPathBuffer.writeToStream(out);
388403
}
389404
}
390405

@@ -394,6 +409,7 @@ void writeToStream(DataOutputStream out) throws IOException {
394409
if (gcRootsComputed) {
395410
leaves = new LongBuffer(dis, heap.cacheDirectory);
396411
multipleParents = new LongBuffer(dis, heap.cacheDirectory);
412+
deepPathBuffer = new LongBuffer(dis, heap.cacheDirectory);
397413
}
398414
}
399415
}

0 commit comments

Comments
 (0)