1 /* 2 * Copyright (c) 2004, 2011, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 * 23 */ 24 25 package sun.jvm.hotspot.tools; 26 27 import sun.jvm.hotspot.tools.*; 28 29 import sun.jvm.hotspot.oops.*; 30 import sun.jvm.hotspot.runtime.VM; 31 import sun.jvm.hotspot.utilities.SystemDictionaryHelper; 32 import sun.jvm.hotspot.utilities.ObjectReader; 33 import sun.jvm.hotspot.utilities.MarkBits; 34 35 import java.util.HashMap; 36 import java.util.ArrayList; 37 import java.util.Collections; 38 import java.util.Comparator; 39 40 /* 41 * Iterates over the queue of object pending finalization and prints a 42 * summary of these objects in the form of a histogram. 43 */ 44 public class FinalizerInfo extends Tool { 45 public static void main(String[] args) { 46 FinalizerInfo finfo = new FinalizerInfo(); 47 finfo.start(args); 48 finfo.stop(); 49 } 50 51 public void run() { 52 /* 53 * The implementation here has a dependency on the implementation of 54 * java.lang.ref.Finalizer. If the Finalizer implementation changes it's 55 * possible this method will require changes too. We looked into using 56 * ObjectReader to deserialize the objects from the target VM but as 57 * there aren't any public methods to traverse the queue it means using 58 * reflection which will also tie us to the implementation. 59 * 60 * The assumption here is that Finalizer.queue is the ReferenceQueue 61 * with the objects awaiting finalization. The ReferenceQueue queueLength 62 * is the number of objects in the queue, and 'head' is the head of the 63 * queue. 64 */ 65 InstanceKlass ik = 66 SystemDictionaryHelper.findInstanceKlass("java.lang.ref.Finalizer"); 67 final Oop[] queueref = new Oop[1]; 68 ik.iterateStaticFields(new DefaultOopVisitor() { 69 public void doOop(OopField field, boolean isVMField) { 70 String name = field.getID().getName(); 71 if (name.equals("queue")) { 72 queueref[0] = field.getValue(getObj()); 73 } 74 } 75 }); 76 Oop queue = queueref[0]; 77 78 InstanceKlass k = (InstanceKlass) queue.getKlass(); 79 80 LongField queueLengthField = (LongField) k.findField("queueLength", "J"); 81 long queueLength = queueLengthField.getValue(queue); 82 83 OopField headField = (OopField) k.findField("head", "Ljava/lang/ref/Reference;"); 84 Oop head = headField.getValue(queue); 85 86 System.out.println("Number of objects pending for finalization: " + queueLength); 87 88 /* 89 * If 'head' is non-NULL then it is the head of a list of References. 90 * We iterate over the list (end of list is when head.next == head) 91 */ 92 if (head != null) { 93 k = (InstanceKlass) head.getKlass(); 94 OopField referentField = 95 (OopField) k.findField("referent", "Ljava/lang/Object;"); 96 OopField nextField = 97 (OopField) k.findField("next", "Ljava/lang/ref/Reference;"); 98 99 HashMap map = new HashMap(); 100 for (;;) { 101 Oop referent = referentField.getValue(head); 102 103 Klass klass = referent.getKlass(); 104 if (!map.containsKey(klass)) { 105 map.put(klass, new ObjectHistogramElement(klass)); 106 } 107 ((ObjectHistogramElement)map.get(klass)).updateWith(referent); 108 109 Oop next = nextField.getValue(head); 110 if (next == null || next.equals(head)) break; 111 head = next; 112 } 113 114 /* 115 * Sort results - decending order by total size 116 */ 117 ArrayList list = new ArrayList(); 118 list.addAll(map.values()); 119 Collections.sort(list, new Comparator() { 120 public int compare(Object o1, Object o2) { 121 return ((ObjectHistogramElement)o1).compare((ObjectHistogramElement)o2); 122 } 123 }); 124 125 /* 126 * Print summary of objects in queue 127 */ 128 System.out.println(""); 129 System.out.println("Count" + "\t" + "Class description"); 130 System.out.println("-------------------------------------------------------"); 131 for (int i=0; i<list.size(); i++) { 132 ObjectHistogramElement e = (ObjectHistogramElement)list.get(i); 133 System.out.println(e.getCount() + "\t" + e.getDescription()); 134 } 135 } 136 137 } 138 }