FULL PRODUCT VERSION : ADDITIONAL OS VERSION INFORMATION : any OS A DESCRIPTION OF THE PROBLEM : I'm filing this ticket after discussion with Sundararajan.A. This is not a bug per se; classification as RFE is ok too. A small change in jhat makes it possible to use jhat to diagnose classloader leaks. See http://blogs.sun.com/fkieviet/entry/classloader_leaks_the_dreaded_java and http://blogs.sun.com/fkieviet/entry/how_to_fix_the_dreaded The change is in Snapshot.java in the method rootsetReferencesTo(). I've tried to change as few lines of code as possible. The change is as follows: when the user asks for references to be traced from a classloader object, it now includes all references from classes to the classloader, and from the instances of these classes to the classloader. Similarly, when the user asks for references to be traced from a class object, it now includes all references from the instances of these classes. The changed method is pasted below: the changes are between the markers FGK and FGK. public ReferenceChain[] rootsetReferencesTo(JavaHeapObject target, boolean includeWeak) { Vector fifo = new Vector(); // This is slow... A real fifo would help // Must be a fifo to go breadth-first Hashtable visited = new Hashtable(); // Objects are added here right after being added to fifo. Vector result = new Vector(); visited.put(target, target); fifo.addElement(new ReferenceChain(target, null)); while (fifo.size() > 0) { ReferenceChain chain = (ReferenceChain) fifo.elementAt(0); fifo.removeElementAt(0); JavaHeapObject curr = chain.getObj(); if (curr.getRoot() != null) { result.addElement(chain); // Even though curr is in the rootset, we want to explore its // referers, because they might be more interesting. } Enumeration referers = curr.getReferers(); while (referers.hasMoreElements()) { JavaHeapObject t = (JavaHeapObject) referers.nextElement(); if (t != null && !visited.containsKey(t)) { if (includeWeak || !t.refersOnlyWeaklyTo(this, curr)) { visited.put(t, t); fifo.addElement(new ReferenceChain(t, chain)); } } } // FGK Special processing when a class is queried: // Include all instances of the sought after class if (target == curr && curr instanceof JavaClass) { JavaClass clazz = (JavaClass) curr; referers = clazz.getInstances(false); // copy & paste from above: go over all objects while (referers.hasMoreElements()) { JavaHeapObject t = (JavaHeapObject) referers.nextElement(); if (t != null && !visited.containsKey(t)) { if (includeWeak || !t.refersOnlyWeaklyTo(this, curr)) { visited.put(t, t); fifo.addElement(new ReferenceChain(t, chain)); } } } } // FGK. // FGK Special processing when a classloader is queried: // Include all instances of classes loaded by this classloader as references if (target == curr && target instanceof JavaObject && findClass("java.lang.ClassLoader").isAssignableFrom(target.getClazz())) { // Find all classes that have this as classloader; for each class add // references for all the class's instances to the classloader for (Iterator iter = classes.values().iterator(); iter.hasNext();) { JavaClass cand = (JavaClass) iter.next(); if (cand.getLoader() == target) { referers = cand.getInstances(false); // copy & paste from above: go over all objects while (referers.hasMoreElements()) { JavaHeapObject t = (JavaHeapObject) referers.nextElement(); if (t != null && !visited.containsKey(t)) { if (includeWeak || !t.refersOnlyWeaklyTo(this, curr)) { visited.put(t, t); fifo.addElement(new ReferenceChain(t, chain)); } } } } } } // FGK. } REPRODUCIBILITY : This bug can be reproduced always.
|