Skip to content

Commit 9bdc174

Browse files
committed
GH-215, incompatible API change - Heap.getGCRoot(Instance instance) now returns Collection not just one GCRoot instance; Heap.getGCRoots() returns all GCRoots including duplicates
1 parent 73bc375 commit 9bdc174

File tree

18 files changed

+543
-401
lines changed

18 files changed

+543
-401
lines changed

visualvm/heapviewer/nbproject/project.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
<compile-dependency/>
2222
<run-dependency>
2323
<release-version>2</release-version>
24-
<specification-version>2.0</specification-version>
24+
<specification-version>2.3</specification-version>
2525
</run-dependency>
2626
</dependency>
2727
<dependency>

visualvm/heapviewer/src/org/graalvm/visualvm/heapviewer/java/InstanceNode.java

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,11 @@
2525

2626
package org.graalvm.visualvm.heapviewer.java;
2727

28+
import java.util.Collection;
29+
import java.util.Collections;
30+
import java.util.HashSet;
2831
import java.util.Objects;
32+
import java.util.Set;
2933
import org.graalvm.visualvm.lib.jfluid.heap.GCRoot;
3034
import org.graalvm.visualvm.lib.jfluid.heap.Heap;
3135
import org.graalvm.visualvm.lib.jfluid.heap.Instance;
@@ -86,11 +90,11 @@ public JavaClass getJavaClass() {
8690
public String getName(Heap heap) {
8791
if (name == null) {
8892
if (heap == null) {
89-
return computeName(instance, (GCRoot)null);
93+
return computeName(instance, Collections.EMPTY_LIST);
9094
} else {
91-
GCRoot gcRoot = heap.getGCRoot(instance);
92-
isGCRoot = gcRoot != null;
93-
name = computeName(instance, gcRoot);
95+
Collection<GCRoot> gcRoots = heap.getGCRoots(instance);
96+
isGCRoot = gcRoots.isEmpty();
97+
name = computeName(instance, gcRoots);
9498
}
9599
}
96100
return name;
@@ -128,13 +132,21 @@ boolean isGCRoot() {
128132

129133

130134
static String computeName(Instance instance, Heap heap) {
131-
GCRoot gcroot = heap == null ? null : heap.getGCRoot(instance);
132-
return computeName(instance, gcroot);
135+
Collection<GCRoot> gcroots = heap == null ? Collections.EMPTY_LIST : heap.getGCRoots(instance);
136+
return computeName(instance, gcroots);
133137
}
134138

135-
private static String computeName(Instance instance, GCRoot gcroot) {
139+
private static String computeName(Instance instance, Collection<GCRoot> gcroots) {
136140
String name = instance.getJavaClass().getName() + "#" + instance.getInstanceNumber(); // NOI18N
137-
if (gcroot != null) name = Bundle.InstanceNode_GCRootFlag(name, gcroot.getKind());
141+
if (!gcroots.isEmpty()) {
142+
Set<String> gcKinds = new HashSet();
143+
144+
for (GCRoot gcroot : gcroots) {
145+
gcKinds.add(gcroot.getKind());
146+
}
147+
String kind = String.join(", ", gcKinds); // NOI18N
148+
name = Bundle.InstanceNode_GCRootFlag(name, kind);
149+
}
138150
return name;
139151
}
140152

visualvm/heapviewer/src/org/graalvm/visualvm/heapviewer/java/impl/JavaThreadsView.java

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import java.awt.event.ActionEvent;
3030
import java.awt.event.ItemEvent;
3131
import java.net.URL;
32+
import java.util.Collection;
3233
import java.util.List;
3334
import javax.swing.ButtonGroup;
3435
import javax.swing.JComponent;
@@ -308,21 +309,22 @@ public HeapViewerNodeAction[] getActions(HeapViewerNode node, HeapContext contex
308309
Instance instance = HeapViewerNode.getValue(node, DataType.INSTANCE, heap);
309310
if (instance == null) return null;
310311

311-
GCRoot gcRoot = heap.getGCRoot(instance);
312-
if (gcRoot == null) return null;
312+
Collection<GCRoot> gcRoots = heap.getGCRoots(instance);
313313

314-
String gcRootKind = gcRoot.getKind();
315-
316-
if (GCRoot.JAVA_FRAME.equals(gcRootKind)) {
317-
JavaFrameGCRoot frameVar = (JavaFrameGCRoot)gcRoot;
318-
if (frameVar.getFrameNumber() == -1) return null;
319-
} else if (GCRoot.THREAD_OBJECT.equals(gcRootKind)) {
320-
// ThreadObjectGCRoot thread = (ThreadObjectGCRoot)gcRoot;
321-
} else {
322-
return null;
314+
for (GCRoot gcRoot : gcRoots) {
315+
String gcRootKind = gcRoot.getKind();
316+
317+
if (GCRoot.JAVA_FRAME.equals(gcRootKind)) {
318+
JavaFrameGCRoot frameVar = (JavaFrameGCRoot)gcRoot;
319+
if (frameVar.getFrameNumber() != -1) {
320+
return new HeapViewerNodeAction[] { new SelectInstanceAction(instance.getInstanceId(), actions) };
321+
}
322+
} else if (GCRoot.THREAD_OBJECT.equals(gcRootKind)) {
323+
// ThreadObjectGCRoot thread = (ThreadObjectGCRoot)gcRoot;
324+
return new HeapViewerNodeAction[] { new SelectInstanceAction(instance.getInstanceId(), actions) };
325+
}
323326
}
324-
325-
return new HeapViewerNodeAction[] { new SelectInstanceAction(instance.getInstanceId(), actions) };
327+
return null;
326328
}
327329

328330
}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
Manifest-Version: 1.0
22
OpenIDE-Module: org.graalvm.visualvm.lib.jfluid/2
33
OpenIDE-Module-Localizing-Bundle: org/graalvm/visualvm/lib/jfluid/Bundle.properties
4-
OpenIDE-Module-Specification-Version: 2.2
4+
OpenIDE-Module-Specification-Version: 2.3
55

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ public List getFieldValues() {
6969
}
7070

7171
public boolean isGCRoot() {
72-
return classDump.getHprof().getGCRoot(this) != null;
72+
return classDump.getHprof().isGCRoot(this);
7373
}
7474

7575
public long getInstanceId() {

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -76,13 +76,13 @@ public interface Heap {
7676
List /*<Instance>*/ getBiggestObjectsByRetainedSize(int number);
7777

7878
/**
79-
* returns {@link GCRoot} for {@link Instance}.
79+
* returns list of {@link GCRoot} for {@link Instance}.
8080
* <br>
8181
* Speed: normal for first invocation, fast for subsequent
82-
* @param instance {@link Instance} whose associated {@link GCRoot} is to be returned.
83-
* @return {@link GCRoot} for corresponding instance or <CODE>null</CODE> if instance is not GC root.
82+
* @param instance {@link Instance} whose associated list of {@link GCRoot} is to be returned.
83+
* @return list of {@link GCRoot} for corresponding instance or empty list if instance is not GC root.
8484
*/
85-
GCRoot getGCRoot(Instance instance);
85+
Collection /*<GCRoot>*/ getGCRoots(Instance instance);
8686

8787
/**
8888
* returns list of all GC roots.

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

Lines changed: 34 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,6 @@
4444
import java.util.ArrayList;
4545
import java.util.Collection;
4646
import java.util.Collections;
47-
import java.util.Comparator;
4847
import java.util.HashMap;
4948
import java.util.Iterator;
5049
import java.util.List;
@@ -70,51 +69,40 @@ class HprofGCRoots {
7069
Collection getGCRoots() {
7170
synchronized (gcRootLock) {
7271
if (gcRoots == null) {
73-
gcRoots = computeGCRootsFor(heap.getHeapTagBound(HprofHeap.ROOT_UNKNOWN));
74-
gcRoots.putAll(computeGCRootsFor(heap.getHeapTagBound(HprofHeap.ROOT_JNI_GLOBAL)));
75-
gcRoots.putAll(computeGCRootsFor(heap.getHeapTagBound(HprofHeap.ROOT_JNI_LOCAL)));
76-
gcRoots.putAll(computeGCRootsFor(heap.getHeapTagBound(HprofHeap.ROOT_JAVA_FRAME)));
77-
gcRoots.putAll(computeGCRootsFor(heap.getHeapTagBound(HprofHeap.ROOT_NATIVE_STACK)));
78-
gcRoots.putAll(computeGCRootsFor(heap.getHeapTagBound(HprofHeap.ROOT_STICKY_CLASS)));
79-
gcRoots.putAll(computeGCRootsFor(heap.getHeapTagBound(HprofHeap.ROOT_THREAD_BLOCK)));
80-
gcRoots.putAll(computeGCRootsFor(heap.getHeapTagBound(HprofHeap.ROOT_MONITOR_USED)));
81-
gcRoots.putAll(computeGCRootsFor(heap.getHeapTagBound(HprofHeap.ROOT_THREAD_OBJECT)));
72+
gcRoots = new HashMap(16384);
73+
gcRootsList = new ArrayList(16384);
74+
computeGCRootsFor(heap.getHeapTagBound(HprofHeap.ROOT_UNKNOWN));
75+
computeGCRootsFor(heap.getHeapTagBound(HprofHeap.ROOT_JNI_GLOBAL));
76+
computeGCRootsFor(heap.getHeapTagBound(HprofHeap.ROOT_JNI_LOCAL));
77+
computeGCRootsFor(heap.getHeapTagBound(HprofHeap.ROOT_JAVA_FRAME));
78+
computeGCRootsFor(heap.getHeapTagBound(HprofHeap.ROOT_NATIVE_STACK));
79+
computeGCRootsFor(heap.getHeapTagBound(HprofHeap.ROOT_STICKY_CLASS));
80+
computeGCRootsFor(heap.getHeapTagBound(HprofHeap.ROOT_THREAD_BLOCK));
81+
computeGCRootsFor(heap.getHeapTagBound(HprofHeap.ROOT_MONITOR_USED));
82+
computeGCRootsFor(heap.getHeapTagBound(HprofHeap.ROOT_THREAD_OBJECT));
8283

8384
// HPROF HEAP 1.0.3
84-
gcRoots.putAll(computeGCRootsFor(heap.getHeapTagBound(HprofHeap.ROOT_INTERNED_STRING)));
85-
gcRoots.putAll(computeGCRootsFor(heap.getHeapTagBound(HprofHeap.ROOT_FINALIZING)));
86-
gcRoots.putAll(computeGCRootsFor(heap.getHeapTagBound(HprofHeap.ROOT_DEBUGGER)));
87-
gcRoots.putAll(computeGCRootsFor(heap.getHeapTagBound(HprofHeap.ROOT_REFERENCE_CLEANUP)));
88-
gcRoots.putAll(computeGCRootsFor(heap.getHeapTagBound(HprofHeap.ROOT_VM_INTERNAL)));
89-
gcRoots.putAll(computeGCRootsFor(heap.getHeapTagBound(HprofHeap.ROOT_JNI_MONITOR)));
85+
computeGCRootsFor(heap.getHeapTagBound(HprofHeap.ROOT_INTERNED_STRING));
86+
computeGCRootsFor(heap.getHeapTagBound(HprofHeap.ROOT_FINALIZING));
87+
computeGCRootsFor(heap.getHeapTagBound(HprofHeap.ROOT_DEBUGGER));
88+
computeGCRootsFor(heap.getHeapTagBound(HprofHeap.ROOT_REFERENCE_CLEANUP));
89+
computeGCRootsFor(heap.getHeapTagBound(HprofHeap.ROOT_VM_INTERNAL));
90+
computeGCRootsFor(heap.getHeapTagBound(HprofHeap.ROOT_JNI_MONITOR));
9091

91-
List rootList = new ArrayList(gcRoots.values());
92-
Collections.sort(rootList, new Comparator() {
93-
public int compare(Object o1, Object o2) {
94-
HprofGCRoot r1 = (HprofGCRoot) o1;
95-
HprofGCRoot r2 = (HprofGCRoot) o2;
96-
int kind = r1.getKind().compareTo(r2.getKind());
97-
98-
if (kind != 0) {
99-
return kind;
100-
}
101-
return Long.compare(r1.getInstanceId(), r2.getInstanceId());
102-
}
103-
});
104-
gcRootsList = Collections.unmodifiableList(rootList);
92+
gcRootsList = Collections.unmodifiableList(gcRootsList);
10593
}
10694

10795
return gcRootsList;
10896
}
10997
}
11098

111-
GCRoot getGCRoot(Long instanceId) {
99+
Object getGCRoots(Long instanceId) {
112100
synchronized (gcRootLock) {
113101
if (gcRoots == null) {
114102
heap.getGCRoots();
115103
}
116104

117-
return (GCRoot) gcRoots.get(instanceId);
105+
return gcRoots.get(instanceId);
118106
}
119107
}
120108

@@ -142,9 +130,7 @@ ThreadObjectGCRoot getThreadGCRoot(int threadSerialNumber) {
142130
}
143131

144132

145-
private Map computeGCRootsFor(TagBounds tagBounds) {
146-
Map roots = new HashMap();
147-
133+
private void computeGCRootsFor(TagBounds tagBounds) {
148134
if (tagBounds != null) {
149135
int rootTag = tagBounds.tag;
150136
long[] offset = new long[] { tagBounds.startOffset };
@@ -161,10 +147,21 @@ private Map computeGCRootsFor(TagBounds tagBounds) {
161147
} else {
162148
root = new HprofGCRoot(this, start);
163149
}
164-
roots.put(Long.valueOf(root.getInstanceId()), root);
150+
Long objectId = Long.valueOf(root.getInstanceId());
151+
Object val = gcRoots.get(objectId);
152+
if (val == null) {
153+
gcRoots.put(objectId, root);
154+
} else if (val instanceof GCRoot) {
155+
Collection vals = new ArrayList(2);
156+
vals.add(val);
157+
vals.add(root);
158+
gcRoots.put(objectId, vals);
159+
} else {
160+
((Collection)val).add(root);
161+
}
162+
gcRootsList.add(root);
165163
}
166164
}
167165
}
168-
return roots;
169166
}
170167
}

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

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -201,9 +201,16 @@ public List getBiggestObjectsByRetainedSize(int number) {
201201
return bigObjects;
202202
}
203203

204-
public GCRoot getGCRoot(Instance instance) {
204+
public Collection getGCRoots(Instance instance) {
205205
Long instanceId = Long.valueOf(instance.getInstanceId());
206-
return gcRoots.getGCRoot(instanceId);
206+
Object gcroot = gcRoots.getGCRoots(instanceId);
207+
if (gcroot == null) {
208+
return Collections.EMPTY_LIST;
209+
}
210+
if (gcroot instanceof GCRoot) {
211+
return Collections.singletonList(gcroot);
212+
}
213+
return Collections.unmodifiableCollection((Collection)gcroot);
207214
}
208215

209216
public Collection getGCRoots() {
@@ -775,7 +782,7 @@ void computeRetainedSize() {
775782
boolean isTreeObj = instanceEntry.isTreeObj();
776783
long instSize = 0;
777784

778-
if (!isTreeObj && (instanceEntry.getNearestGCRootPointer() != 0 || gcRoots.getGCRoot(new Long(instanceId)) != null)) {
785+
if (!isTreeObj && (instanceEntry.getNearestGCRootPointer() != 0 || gcRoots.getGCRoots(new Long(instanceId)) != null)) {
779786
long origSize = instanceEntry.getRetainedSize();
780787
if (origSize < 0) origSize = 0;
781788
Instance instance = getInstanceByID(instanceId);
@@ -851,6 +858,11 @@ Instance getNearestGCRootPointer(Instance instance) {
851858
return nearestGCRoot.getNearestGCRootPointer(instance);
852859
}
853860

861+
boolean isGCRoot(Instance instance) {
862+
Long instanceId = Long.valueOf(instance.getInstanceId());
863+
return gcRoots.getGCRoots(instanceId) != null;
864+
}
865+
854866
int readDumpTag(long[] offset) {
855867
long position = offset[0];
856868
int dumpTag = dumpBuffer.get(position++) & 0xFF;

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ public List getFieldValues() {
8888
}
8989

9090
public boolean isGCRoot() {
91-
return getHprof().getGCRoot(this) != null;
91+
return getHprof().isGCRoot(this);
9292
}
9393

9494
public long getInstanceId() {

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ class NearestGCRoot {
9797
//~ Methods ------------------------------------------------------------------------------------------------------------------
9898

9999
Instance getNearestGCRootPointer(Instance instance) {
100-
if (heap.getGCRoot(instance) != null) {
100+
if (heap.isGCRoot(instance)) {
101101
return instance;
102102
}
103103
computeGCRoots();
@@ -337,7 +337,7 @@ private boolean writeConnection(long instanceId, long refInstanceId, boolean add
337337
if (refInstanceId != 0) {
338338
LongMap.Entry entry = heap.idToOffsetMap.get(refInstanceId);
339339

340-
if (entry != null && entry.getNearestGCRootPointer() == 0L && heap.gcRoots.getGCRoot(refInstanceId) == null) {
340+
if (entry != null && entry.getNearestGCRootPointer() == 0L && heap.gcRoots.getGCRoots(refInstanceId) == null) {
341341
writeLong(entry.getOffset());
342342
if (addRefInstanceId) {
343343
if (!checkReferences(refInstanceId, instanceId)) {

0 commit comments

Comments
 (0)