--- old/src/java.base/share/classes/java/lang/ref/Finalizer.java 2015-05-12 19:27:44.884401773 +0300 +++ new/src/java.base/share/classes/java/lang/ref/Finalizer.java 2015-05-12 19:27:44.590396097 +0300 @@ -31,6 +31,12 @@ import sun.misc.SharedSecrets; import sun.misc.VM; +import java.util.Map; +import java.util.Map.Entry; +import java.util.List; +import java.util.ArrayList; +import java.util.Collections; + final class Finalizer extends FinalReference { /* Package-private; must be in same package as the Reference class */ @@ -105,6 +111,23 @@ super.clear(); } + static String printFinalizationQueue() { + StringBuilder sb = new StringBuilder(); + Map countMap = queue.countInstances(); + if (countMap != null) { + List> fins = + new ArrayList<>(countMap.size()); + fins.addAll(countMap.entrySet()); + Collections.sort(fins, (e1, e2) -> e2.getValue().compareTo(e1.getValue())); + + for (Map.Entry e : fins) { + sb.append("Class: " + e.getKey() + " count: " + e.getValue() + "\n"); + } + } + return sb.toString(); + } + + /* Create a privileged secondary finalizer thread in the system thread group for the given Runnable, and wait for it to complete. --- old/src/java.base/share/classes/java/lang/ref/ReferenceQueue.java 2015-05-12 19:27:45.522414091 +0300 +++ new/src/java.base/share/classes/java/lang/ref/ReferenceQueue.java 2015-05-12 19:27:45.229408434 +0300 @@ -25,6 +25,9 @@ package java.lang.ref; +import java.util.HashMap; +import java.util.Map; + /** * Reference queues, to which registered reference objects are appended by the * garbage collector after the appropriate reachability changes are detected. @@ -46,6 +49,16 @@ } } + static class mutableInt { + private int value = 1; + + public void increment(){ value += 1; } + public int getValue(){ return value; } + public int compareTo(mutableInt e){ return getValue() - e.getValue(); } + + public String toString(){ return Integer.toString(value); } + } + static ReferenceQueue NULL = new Null<>(); static ReferenceQueue ENQUEUED = new Null<>(); @@ -110,6 +123,41 @@ } /** + * Iterate queue and cout the number of instances of each object type pending finalization + * + * @return Map of object types with associated counts + */ + @SuppressWarnings("unchecked") + public Map countInstances() { + if (head == null) { + return null; + } + + HashMap countMap = new HashMap<>(); + + synchronized (lock) { + Reference r = head; + if (r != null) { + Object referent = r.get(); + if (referent != null) { + String typeName = referent.getClass().getName(); + mutableInt v = countMap.get(typeName); + if (v == null) { + countMap.put(typeName, new mutableInt()); + } + else { + v.increment(); + } + } + r = r.next; + } + } + + return countMap; + } + + + /** * Removes the next reference object in this queue, blocking until either * one becomes available or the given timeout period expires. *