3131import static org .junit .Assert .assertEquals ;
3232import static org .junit .Assert .assertFalse ;
3333import static org .junit .Assert .assertNotNull ;
34+ import static org .junit .Assert .assertNull ;
35+ import static org .junit .Assert .assertTrue ;
3436import org .junit .Test ;
3537import org .netbeans .lib .profiler .heap .HeapUtils .HprofGenerator ;
3638
@@ -45,6 +47,67 @@ public void singleObjectMultipleSegments() throws IOException {
4547 singleObject (true );
4648 }
4749
50+ @ Test
51+ public void stickyClassRootKeepsStaticReferencesReachable () throws IOException {
52+ File mydump = File .createTempFile ("mydump" , ".hprof" );
53+ final int [] targetId = new int [1 ];
54+ try (HprofGenerator gen = new HprofGenerator (new FileOutputStream (mydump ))) {
55+ gen .writeHeapSegment (new HprofGenerator .Generator <HprofGenerator .HeapSegment >() {
56+ @ Override
57+ public void generate (HprofGenerator .HeapSegment seg ) throws IOException {
58+ seg .newClass ("java.lang.Class" ).dumpClass ();
59+ seg .newClass ("com.oracle.svm.core.heap.heapImpl.DiscoverableReference" )
60+ .addField ("rawReferent" , Object .class )
61+ .dumpClass ();
62+ HprofGenerator .ClassInstance targetClass = seg .newClass ("text.Target" ).dumpClass ();
63+ targetId [0 ] = seg .dumpInstance (targetClass );
64+ HprofGenerator .ClassInstance rootClass = seg .newClass ("text.Root" )
65+ .addStaticObjectField ("target" , targetId [0 ])
66+ .dumpClass ();
67+ seg .dumpStickyClassRoot (rootClass );
68+ }
69+ }, true );
70+ }
71+
72+ Heap heap = HeapFactory .createHeap (mydump );
73+ assertEquals ("One sticky class root" , 1 , heap .getGCRoots ().size ());
74+ GCRoot root = (GCRoot ) heap .getGCRoots ().iterator ().next ();
75+ Instance rootInstance = root .getInstance ();
76+ assertTrue ("Class object instance" , rootInstance instanceof ClassDumpInstance );
77+ assertEquals ("Root found by class object ID" , root , heap .getGCRoot (rootInstance ));
78+
79+ Instance target = heap .getInstanceByID (targetId [0 ]);
80+ assertNotNull ("Static field target" , target );
81+ heap .getBiggestObjectsByRetainedSize (1 );
82+ assertEquals ("Target reached from sticky class" , rootInstance , target .getNearestGCRootPointer ());
83+ assertTrue ("Sticky class retains its static target" , rootInstance .getRetainedSize () > rootInstance .getSize ());
84+ }
85+
86+ @ Test
87+ public void unresolvedStickyClassRootDoesNotBreakRetainedSize () throws IOException {
88+ File mydump = File .createTempFile ("mydump" , ".hprof" );
89+ try (HprofGenerator gen = new HprofGenerator (new FileOutputStream (mydump ))) {
90+ gen .writeHeapSegment (new HprofGenerator .Generator <HprofGenerator .HeapSegment >() {
91+ @ Override
92+ public void generate (HprofGenerator .HeapSegment seg ) throws IOException {
93+ seg .newClass ("java.lang.Class" ).dumpClass ();
94+ seg .newClass ("com.oracle.svm.core.heap.heapImpl.DiscoverableReference" )
95+ .addField ("rawReferent" , Object .class )
96+ .dumpClass ();
97+ HprofGenerator .ClassInstance ordinaryClass = seg .newClass ("text.Ordinary" ).dumpClass ();
98+ seg .dumpInstance (ordinaryClass );
99+ seg .dumpStickyClassRoot (Integer .MAX_VALUE );
100+ }
101+ }, true );
102+ }
103+
104+ Heap heap = HeapFactory .createHeap (mydump );
105+ assertEquals ("One unresolved sticky class root" , 1 , heap .getGCRoots ().size ());
106+ GCRoot root = (GCRoot ) heap .getGCRoots ().iterator ().next ();
107+ assertNull ("No heap object for unresolved root" , root .getInstance ());
108+ assertNotNull ("Retained-size computation completes" , heap .getBiggestObjectsByRetainedSize (1 ));
109+ }
110+
48111 private static void singleObject (boolean flush ) throws IOException {
49112 File mydump = File .createTempFile ("mydump" , ".hprof" );
50113 Heap heap = generateSampleDump (mydump , flush );
0 commit comments