!7 lib 1400084 // patched heap analyzer import org.gridkit.jvmtool.heapdump.*; import org.netbeans.lib.profiler.heap.*; import java.lang.reflect.Field; static Heap heap; sbool fake = false; sbool usePatch = false; p-experiment { File f = stefansOS_heapDumpFile(); print("Loading heap dump (" + toM(fileSize(f)) + " M)..."); heap = HeapFactory.createHeap(f); print("Got heap."); L classes = heap.getAllClasses(); print("Got " + n2(classes, "class", "classes")); //pnl(sortedIC(mapMethod(classes, 'getName))); L classLoaderClasses = filter(classes, func(JavaClass c) -> bool { startsWithOneOf(c.getName(), "main$JavaXClassLoader", "x30$JavaXClassLoader") }); print("Got " + n2(classLoaderClasses, "class loader class", "class loader classes")); L classLoaders = concatLists(mapMethod('getInstances, classLoaderClasses)); print("Got " + n2(classLoaders, "class loader")); L defunctClassLoaders = filter(classLoaders, func(Instance cl) { isTrue(cl.getValueOfField('retired)) }); print("Got " + n2(defunctClassLoaders, "defunct class loader")); print(); if (empty(defunctClassLoaders)) { if (fake) { defunctClassLoaders = classLoaders; print("FAKING IT"); } else { print("No memory leaks."); ret; } } print("Calculating GC roots..."); for (Instance cl : defunctClassLoaders) { Instance progIDInstance = (Instance) cl.getValueOfField('progID); S moduleID = (usePatch ? stringValue_java10(progIDInstance) : HeapWalker.stringValue(progIDInstance)); print("Checking module ID: " + snippetWithTitle_cached(moduleID)); print("\nPath to GC root:"); printLinesWithGrowingIndent(map(func(Instance i) -> S { i.getJavaClass().getName() }, pathToGCRoot(cl))); print(); //Instance i = cl.getNearestGCRootPointer(); //print("i => " + i); } } static L pathToGCRoot(Instance i) { new L path; while licensed { path.add(i); Instance j = i.getNearestGCRootPointer(); if (j == null) null; // No path to GC root? if (j == i) break; i = j; } ret path; } static int lengthOfPathToGCRoot(Instance i) { int n = 0; while licensed { if (i == null) ret -1; // No path to GC root? Instance j = i.getNearestGCRootPointer(); if (j == i) ret n; i = j; ++n; } ret -2; // dummy when program got unlicensed } static S stringValue_java10(Instance obj) { if (obj == null) null; if (!"java.lang.String".equals(obj.getJavaClass().getName())) throw new IllegalArgumentException("Is not a string: " + obj.getInstanceId() + " (" + obj.getJavaClass().getName() + ")"); int UTF16 = 1; Bool COMPACT_STRINGS = cast obj.getJavaClass().getValueOfStaticField("COMPACT_STRINGS"); if (COMPACT_STRINGS == null) ret HeapWalker.stringValue(obj); // We're pre Java 9 O valueInstance = obj.getValueOfField("value"); PrimitiveArrayInstance chars = cast valueInstance; byte coderField = cast obj.getValueOfField("coder"); byte coder = COMPACT_STRINGS ? coderField : (byte) UTF16; int len = chars.getLength() >> coder; char[] text = new char[len]; L values = (L) chars.getValues(); if (coder == UTF16) for (int i = 0; i < text.length; i++) text[i] = values.get(i).charAt(0); else for (int i = 0; i < text.length; i++) text[i] = (char) Int.parseInt(values.get(i)); ret new String(text); }