8008536: Add HotSpot support for printing class loader statistics for JMap
Reviewed-by: sla, brutisso
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/tools/ClassLoaderStats.java Wed Feb 20 16:41:23 2013 +0100
@@ -0,0 +1,277 @@
+/*
+ * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+package sun.jvm.hotspot.tools;
+
+import java.io.*;
+import java.util.*;
+
+import sun.jvm.hotspot.debugger.*;
+import sun.jvm.hotspot.memory.*;
+import sun.jvm.hotspot.oops.*;
+import sun.jvm.hotspot.runtime.*;
+import sun.jvm.hotspot.tools.*;
+import sun.jvm.hotspot.utilities.*;
+
+/**
+ A command line tool to print class loader statistics.
+*/
+
+public class ClassLoaderStats extends Tool {
+ boolean verbose = true;
+
+ public static void main(String[] args) {
+ ClassLoaderStats cls = new ClassLoaderStats();
+ cls.start(args);
+ cls.stop();
+ }
+
+ private static class ClassData {
+ Klass klass;
+ long size;
+
+ ClassData(Klass klass, long size) {
+ this.klass = klass; this.size = size;
+ }
+ }
+
+ private static class LoaderData {
+ long numClasses;
+ long classSize;
+ List classDetail = new ArrayList(); // List<ClassData>
+ }
+
+ public void run() {
+ printClassLoaderStatistics();
+ }
+
+ private void printClassLoaderStatistics() {
+ final PrintStream out = System.out;
+ final PrintStream err = System.err;
+ final Map loaderMap = new HashMap();
+ // loader data for bootstrap class loader
+ final LoaderData bootstrapLoaderData = new LoaderData();
+ if (verbose) {
+ err.print("finding class loader instances ..");
+ }
+
+ VM vm = VM.getVM();
+ ObjectHeap heap = vm.getObjectHeap();
+ Klass classLoaderKlass = vm.getSystemDictionary().getClassLoaderKlass();
+ try {
+ heap.iterateObjectsOfKlass(new DefaultHeapVisitor() {
+ public boolean doObj(Oop oop) {
+ loaderMap.put(oop, new LoaderData());
+ return false;
+ }
+ }, classLoaderKlass);
+ } catch (Exception se) {
+ se.printStackTrace();
+ }
+
+ if (verbose) {
+ err.println("done.");
+ err.print("computing per loader stat ..");
+ }
+
+ SystemDictionary dict = VM.getVM().getSystemDictionary();
+ dict.classesDo(new SystemDictionary.ClassAndLoaderVisitor() {
+ public void visit(Klass k, Oop loader) {
+ if (! (k instanceof InstanceKlass)) {
+ return;
+ }
+ LoaderData ld = (loader != null) ? (LoaderData)loaderMap.get(loader)
+ : bootstrapLoaderData;
+ if (ld != null) {
+ ld.numClasses++;
+ long size = computeSize((InstanceKlass)k);
+ ld.classDetail.add(new ClassData(k, size));
+ ld.classSize += size;
+ }
+ }
+ });
+
+ if (verbose) {
+ err.println("done.");
+ err.print("please wait.. computing liveness");
+ }
+
+ // compute reverse pointer analysis (takes long time for larger app)
+ ReversePtrsAnalysis analysis = new ReversePtrsAnalysis();
+
+ if (verbose) {
+ analysis.setHeapProgressThunk(new HeapProgressThunk() {
+ public void heapIterationFractionUpdate(double fractionOfHeapVisited) {
+ err.print('.');
+ }
+ // This will be called after the iteration is complete
+ public void heapIterationComplete() {
+ err.println("done.");
+ }
+ });
+ }
+
+ try {
+ analysis.run();
+ } catch (Exception e) {
+ // e.printStackTrace();
+ if (verbose)
+ err.println("liveness analysis may be inaccurate ...");
+ }
+ ReversePtrs liveness = VM.getVM().getRevPtrs();
+
+ out.println("class_loader\tclasses\tbytes\tparent_loader\talive?\ttype");
+ out.println();
+
+ long numClassLoaders = 1L;
+ long totalNumClasses = bootstrapLoaderData.numClasses;
+ long totalClassSize = bootstrapLoaderData.classSize;
+ long numAliveLoaders = 1L;
+ long numDeadLoaders = 0L;
+
+ // print bootstrap loader details
+ out.print("<bootstrap>");
+ out.print('\t');
+ out.print(bootstrapLoaderData.numClasses);
+ out.print('\t');
+ out.print(bootstrapLoaderData.classSize);
+ out.print('\t');
+ out.print(" null ");
+ out.print('\t');
+ // bootstrap loader is always alive
+ out.print("live");
+ out.print('\t');
+ out.println("<internal>");
+
+ for (Iterator keyItr = loaderMap.keySet().iterator(); keyItr.hasNext();) {
+ Oop loader = (Oop) keyItr.next();
+ LoaderData data = (LoaderData) loaderMap.get(loader);
+ numClassLoaders ++;
+ totalNumClasses += data.numClasses;
+ totalClassSize += data.classSize;
+
+ out.print(loader.getHandle());
+ out.print('\t');
+ out.print(data.numClasses);
+ out.print('\t');
+ out.print(data.classSize);
+ out.print('\t');
+
+ class ParentFinder extends DefaultOopVisitor {
+ public void doOop(OopField field, boolean isVMField) {
+ if (field.getID().getName().equals("parent")) {
+ parent = field.getValue(getObj());
+ }
+ }
+ private Oop parent = null;
+ public Oop getParent() { return parent; }
+ }
+
+ ParentFinder parentFinder = new ParentFinder();
+ loader.iterate(parentFinder, false);
+ Oop parent = parentFinder.getParent();
+ out.print((parent != null)? parent.getHandle().toString() : " null ");
+ out.print('\t');
+ boolean alive = (liveness != null) ? (liveness.get(loader) != null) : true;
+ out.print(alive? "live" : "dead");
+ if (alive) numAliveLoaders++; else numDeadLoaders++;
+ out.print('\t');
+ Klass loaderKlass = loader.getKlass();
+ if (loaderKlass != null) {
+ out.print(loaderKlass.getName().asString());
+ out.print('@');
+ out.print(loader.getKlass().getAddress());
+ } else {
+ out.print(" null! ");
+ }
+ out.println();
+ }
+
+ out.println();
+ // summary line
+ out.print("total = ");
+ out.print(numClassLoaders);
+ out.print('\t');
+ out.print(totalNumClasses);
+ out.print('\t');
+ out.print(totalClassSize);
+ out.print('\t');
+ out.print(" N/A ");
+ out.print('\t');
+ out.print("alive=");
+ out.print(numAliveLoaders);
+ out.print(", dead=");
+ out.print(numDeadLoaders);
+ out.print('\t');
+ out.print(" N/A ");
+ out.println();
+ }
+
+ private static long objectSize(Oop oop) {
+ return oop == null ? 0L : oop.getObjectSize();
+ }
+
+ // Don't count the shared empty arrays
+ private static long arraySize(GenericArray arr) {
+ return arr.getLength() != 0L ? arr.getSize() : 0L;
+ }
+
+ private long computeSize(InstanceKlass k) {
+ long size = 0L;
+ // the InstanceKlass object itself
+ size += k.getSize();
+
+ // Constant pool
+ ConstantPool cp = k.getConstants();
+ size += cp.getSize();
+ if (cp.getCache() != null) {
+ size += cp.getCache().getSize();
+ }
+ size += arraySize(cp.getTags());
+
+ // Interfaces
+ size += arraySize(k.getLocalInterfaces());
+ size += arraySize(k.getTransitiveInterfaces());
+
+ // Inner classes
+ size += arraySize(k.getInnerClasses());
+
+ // Fields
+ size += arraySize(k.getFields());
+
+ // Methods
+ MethodArray methods = k.getMethods();
+ int nmethods = (int) methods.getLength();
+ if (nmethods != 0L) {
+ size += methods.getSize();
+ for (int i = 0; i < nmethods; ++i) {
+ Method m = methods.at(i);
+ size += m.getSize();
+ size += m.getConstMethod().getSize();
+ }
+ }
+
+ return size;
+ }
+}
--- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/tools/JMap.java Tue Feb 26 11:52:06 2013 +0100
+++ b/hotspot/agent/src/share/classes/sun/jvm/hotspot/tools/JMap.java Wed Feb 20 16:41:23 2013 +0100
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2004, 2007, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2004, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -45,7 +45,7 @@
}
protected String getCommandFlags() {
- return "-heap|-heap:format=b|-histo|-permstat|-finalizerinfo";
+ return "-heap|-heap:format=b|-histo|-clstats|-finalizerinfo";
}
protected void printFlagsUsage() {
@@ -53,14 +53,14 @@
System.out.println(" -heap\tto print java heap summary");
System.out.println(" -heap:format=b\tto dump java heap in hprof binary format");
System.out.println(" -histo\tto print histogram of java object heap");
- System.out.println(" -permstat\tto print permanent generation statistics");
+ System.out.println(" -clstats\tto print class loader statistics");
System.out.println(" -finalizerinfo\tto print information on objects awaiting finalization");
super.printFlagsUsage();
}
public static final int MODE_HEAP_SUMMARY = 0;
public static final int MODE_HISTOGRAM = 1;
- public static final int MODE_PERMSTAT = 2;
+ public static final int MODE_CLSTATS = 2;
public static final int MODE_PMAP = 3;
public static final int MODE_HEAP_GRAPH_HPROF_BIN = 4;
public static final int MODE_HEAP_GRAPH_GXL = 5;
@@ -78,8 +78,8 @@
tool = new ObjectHistogram();
break;
- case MODE_PERMSTAT:
- tool = new PermStat();
+ case MODE_CLSTATS:
+ tool = new ClassLoaderStats();
break;
case MODE_PMAP:
@@ -118,7 +118,9 @@
} else if (modeFlag.equals("-histo")) {
mode = MODE_HISTOGRAM;
} else if (modeFlag.equals("-permstat")) {
- mode = MODE_PERMSTAT;
+ mode = MODE_CLSTATS;
+ } else if (modeFlag.equals("-clstats")) {
+ mode = MODE_CLSTATS;
} else if (modeFlag.equals("-finalizerinfo")) {
mode = MODE_FINALIZERINFO;
} else {
--- a/hotspot/agent/src/share/classes/sun/jvm/hotspot/tools/PermStat.java Tue Feb 26 11:52:06 2013 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,277 +0,0 @@
-/*
- * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
- * or visit www.oracle.com if you need additional information or have any
- * questions.
- *
- */
-
-package sun.jvm.hotspot.tools;
-
-import java.io.*;
-import java.util.*;
-
-import sun.jvm.hotspot.debugger.*;
-import sun.jvm.hotspot.memory.*;
-import sun.jvm.hotspot.oops.*;
-import sun.jvm.hotspot.runtime.*;
-import sun.jvm.hotspot.tools.*;
-import sun.jvm.hotspot.utilities.*;
-
-/**
- A command line tool to print perm. generation statistics.
-*/
-
-public class PermStat extends Tool {
- boolean verbose = true;
-
- public static void main(String[] args) {
- PermStat ps = new PermStat();
- ps.start(args);
- ps.stop();
- }
-
- private static class ClassData {
- Klass klass;
- long size;
-
- ClassData(Klass klass, long size) {
- this.klass = klass; this.size = size;
- }
- }
-
- private static class LoaderData {
- long numClasses;
- long classSize;
- List classDetail = new ArrayList(); // List<ClassData>
- }
-
- public void run() {
- printClassLoaderStatistics();
- }
-
- private void printClassLoaderStatistics() {
- final PrintStream out = System.out;
- final PrintStream err = System.err;
- final Map loaderMap = new HashMap();
- // loader data for bootstrap class loader
- final LoaderData bootstrapLoaderData = new LoaderData();
- if (verbose) {
- err.print("finding class loader instances ..");
- }
-
- VM vm = VM.getVM();
- ObjectHeap heap = vm.getObjectHeap();
- Klass classLoaderKlass = vm.getSystemDictionary().getClassLoaderKlass();
- try {
- heap.iterateObjectsOfKlass(new DefaultHeapVisitor() {
- public boolean doObj(Oop oop) {
- loaderMap.put(oop, new LoaderData());
- return false;
- }
- }, classLoaderKlass);
- } catch (Exception se) {
- se.printStackTrace();
- }
-
- if (verbose) {
- err.println("done.");
- err.print("computing per loader stat ..");
- }
-
- SystemDictionary dict = VM.getVM().getSystemDictionary();
- dict.classesDo(new SystemDictionary.ClassAndLoaderVisitor() {
- public void visit(Klass k, Oop loader) {
- if (! (k instanceof InstanceKlass)) {
- return;
- }
- LoaderData ld = (loader != null) ? (LoaderData)loaderMap.get(loader)
- : bootstrapLoaderData;
- if (ld != null) {
- ld.numClasses++;
- long size = computeSize((InstanceKlass)k);
- ld.classDetail.add(new ClassData(k, size));
- ld.classSize += size;
- }
- }
- });
-
- if (verbose) {
- err.println("done.");
- err.print("please wait.. computing liveness");
- }
-
- // compute reverse pointer analysis (takes long time for larger app)
- ReversePtrsAnalysis analysis = new ReversePtrsAnalysis();
-
- if (verbose) {
- analysis.setHeapProgressThunk(new HeapProgressThunk() {
- public void heapIterationFractionUpdate(double fractionOfHeapVisited) {
- err.print('.');
- }
- // This will be called after the iteration is complete
- public void heapIterationComplete() {
- err.println("done.");
- }
- });
- }
-
- try {
- analysis.run();
- } catch (Exception e) {
- // e.printStackTrace();
- if (verbose)
- err.println("liveness analysis may be inaccurate ...");
- }
- ReversePtrs liveness = VM.getVM().getRevPtrs();
-
- out.println("class_loader\tclasses\tbytes\tparent_loader\talive?\ttype");
- out.println();
-
- long numClassLoaders = 1L;
- long totalNumClasses = bootstrapLoaderData.numClasses;
- long totalClassSize = bootstrapLoaderData.classSize;
- long numAliveLoaders = 1L;
- long numDeadLoaders = 0L;
-
- // print bootstrap loader details
- out.print("<bootstrap>");
- out.print('\t');
- out.print(bootstrapLoaderData.numClasses);
- out.print('\t');
- out.print(bootstrapLoaderData.classSize);
- out.print('\t');
- out.print(" null ");
- out.print('\t');
- // bootstrap loader is always alive
- out.print("live");
- out.print('\t');
- out.println("<internal>");
-
- for (Iterator keyItr = loaderMap.keySet().iterator(); keyItr.hasNext();) {
- Oop loader = (Oop) keyItr.next();
- LoaderData data = (LoaderData) loaderMap.get(loader);
- numClassLoaders ++;
- totalNumClasses += data.numClasses;
- totalClassSize += data.classSize;
-
- out.print(loader.getHandle());
- out.print('\t');
- out.print(data.numClasses);
- out.print('\t');
- out.print(data.classSize);
- out.print('\t');
-
- class ParentFinder extends DefaultOopVisitor {
- public void doOop(OopField field, boolean isVMField) {
- if (field.getID().getName().equals("parent")) {
- parent = field.getValue(getObj());
- }
- }
- private Oop parent = null;
- public Oop getParent() { return parent; }
- }
-
- ParentFinder parentFinder = new ParentFinder();
- loader.iterate(parentFinder, false);
- Oop parent = parentFinder.getParent();
- out.print((parent != null)? parent.getHandle().toString() : " null ");
- out.print('\t');
- boolean alive = (liveness != null) ? (liveness.get(loader) != null) : true;
- out.print(alive? "live" : "dead");
- if (alive) numAliveLoaders++; else numDeadLoaders++;
- out.print('\t');
- Klass loaderKlass = loader.getKlass();
- if (loaderKlass != null) {
- out.print(loaderKlass.getName().asString());
- out.print('@');
- out.print(loader.getKlass().getAddress());
- } else {
- out.print(" null! ");
- }
- out.println();
- }
-
- out.println();
- // summary line
- out.print("total = ");
- out.print(numClassLoaders);
- out.print('\t');
- out.print(totalNumClasses);
- out.print('\t');
- out.print(totalClassSize);
- out.print('\t');
- out.print(" N/A ");
- out.print('\t');
- out.print("alive=");
- out.print(numAliveLoaders);
- out.print(", dead=");
- out.print(numDeadLoaders);
- out.print('\t');
- out.print(" N/A ");
- out.println();
- }
-
- private static long objectSize(Oop oop) {
- return oop == null ? 0L : oop.getObjectSize();
- }
-
- // Don't count the shared empty arrays
- private static long arraySize(GenericArray arr) {
- return arr.getLength() != 0L ? arr.getSize() : 0L;
- }
-
- private long computeSize(InstanceKlass k) {
- long size = 0L;
- // the InstanceKlass object itself
- size += k.getSize();
-
- // Constant pool
- ConstantPool cp = k.getConstants();
- size += cp.getSize();
- if (cp.getCache() != null) {
- size += cp.getCache().getSize();
- }
- size += arraySize(cp.getTags());
-
- // Interfaces
- size += arraySize(k.getLocalInterfaces());
- size += arraySize(k.getTransitiveInterfaces());
-
- // Inner classes
- size += arraySize(k.getInnerClasses());
-
- // Fields
- size += arraySize(k.getFields());
-
- // Methods
- MethodArray methods = k.getMethods();
- int nmethods = (int) methods.getLength();
- if (nmethods != 0L) {
- size += methods.getSize();
- for (int i = 0; i < nmethods; ++i) {
- Method m = methods.at(i);
- size += m.getSize();
- size += m.getConstMethod().getSize();
- }
- }
-
- return size;
- }
-}