ClassLoaderStats.java revision 9883:903a2e023ffb
1251881Speter/* 2251881Speter * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved. 3251881Speter * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4251881Speter * 5251881Speter * This code is free software; you can redistribute it and/or modify it 6251881Speter * under the terms of the GNU General Public License version 2 only, as 7251881Speter * published by the Free Software Foundation. 8251881Speter * 9251881Speter * This code is distributed in the hope that it will be useful, but WITHOUT 10251881Speter * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11251881Speter * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12251881Speter * version 2 for more details (a copy is included in the LICENSE file that 13251881Speter * accompanied this code). 14251881Speter * 15251881Speter * You should have received a copy of the GNU General Public License version 16251881Speter * 2 along with this work; if not, write to the Free Software Foundation, 17251881Speter * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18251881Speter * 19251881Speter * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20251881Speter * or visit www.oracle.com if you need additional information or have any 21251881Speter * questions. 22251881Speter * 23251881Speter */ 24251881Speter 25251881Speterpackage sun.jvm.hotspot.tools; 26251881Speter 27251881Speterimport java.io.*; 28251881Speterimport java.util.*; 29251881Speter 30251881Speterimport sun.jvm.hotspot.debugger.*; 31251881Speterimport sun.jvm.hotspot.memory.*; 32251881Speterimport sun.jvm.hotspot.oops.*; 33251881Speterimport sun.jvm.hotspot.runtime.*; 34251881Speterimport sun.jvm.hotspot.tools.*; 35251881Speterimport sun.jvm.hotspot.utilities.*; 36251881Speter 37251881Speter/** 38251881Speter A command line tool to print class loader statistics. 39251881Speter*/ 40251881Speter 41251881Speterpublic class ClassLoaderStats extends Tool { 42251881Speter boolean verbose = true; 43251881Speter 44251881Speter public ClassLoaderStats() { 45251881Speter super(); 46251881Speter } 47251881Speter 48251881Speter public ClassLoaderStats(JVMDebugger d) { 49251881Speter super(d); 50251881Speter } 51251881Speter 52251881Speter public static void main(String[] args) { 53251881Speter ClassLoaderStats cls = new ClassLoaderStats(); 54251881Speter cls.execute(args); 55251881Speter } 56251881Speter 57251881Speter private static class ClassData { 58251881Speter Klass klass; 59251881Speter long size; 60251881Speter 61251881Speter ClassData(Klass klass, long size) { 62251881Speter this.klass = klass; this.size = size; 63251881Speter } 64251881Speter } 65251881Speter 66251881Speter private static class LoaderData { 67251881Speter long numClasses; 68251881Speter long classSize; 69251881Speter List classDetail = new ArrayList(); // List<ClassData> 70251881Speter } 71251881Speter 72251881Speter public void run() { 73251881Speter printClassLoaderStatistics(); 74251881Speter } 75251881Speter 76251881Speter private void printClassLoaderStatistics() { 77251881Speter final PrintStream out = System.out; 78251881Speter final PrintStream err = System.err; 79251881Speter final Map loaderMap = new HashMap(); 80251881Speter // loader data for bootstrap class loader 81251881Speter final LoaderData bootstrapLoaderData = new LoaderData(); 82251881Speter if (verbose) { 83251881Speter err.print("finding class loader instances .."); 84251881Speter } 85251881Speter 86251881Speter VM vm = VM.getVM(); 87251881Speter ObjectHeap heap = vm.getObjectHeap(); 88251881Speter Klass classLoaderKlass = vm.getSystemDictionary().getClassLoaderKlass(); 89251881Speter try { 90251881Speter heap.iterateObjectsOfKlass(new DefaultHeapVisitor() { 91251881Speter public boolean doObj(Oop oop) { 92251881Speter loaderMap.put(oop, new LoaderData()); 93251881Speter return false; 94251881Speter } 95251881Speter }, classLoaderKlass); 96251881Speter } catch (Exception se) { 97251881Speter se.printStackTrace(); 98251881Speter } 99251881Speter 100251881Speter if (verbose) { 101251881Speter err.println("done."); 102251881Speter err.print("computing per loader stat .."); 103251881Speter } 104251881Speter 105251881Speter SystemDictionary dict = VM.getVM().getSystemDictionary(); 106251881Speter dict.classesDo(new SystemDictionary.ClassVisitor() { 107251881Speter public void visit(Klass k) { 108251881Speter if (! (k instanceof InstanceKlass)) { 109251881Speter return; 110251881Speter } 111251881Speter Oop loader = ((InstanceKlass) k).getClassLoader(); 112251881Speter LoaderData ld = (loader != null) ? (LoaderData)loaderMap.get(loader) 113251881Speter : bootstrapLoaderData; 114251881Speter if (ld != null) { 115251881Speter ld.numClasses++; 116251881Speter long size = computeSize((InstanceKlass)k); 117251881Speter ld.classDetail.add(new ClassData(k, size)); 118251881Speter ld.classSize += size; 119251881Speter } 120251881Speter } 121251881Speter }); 122251881Speter 123251881Speter if (verbose) { 124251881Speter err.println("done."); 125251881Speter err.print("please wait.. computing liveness"); 126251881Speter } 127251881Speter 128251881Speter // compute reverse pointer analysis (takes long time for larger app) 129251881Speter ReversePtrsAnalysis analysis = new ReversePtrsAnalysis(); 130251881Speter 131251881Speter if (verbose) { 132251881Speter analysis.setHeapProgressThunk(new HeapProgressThunk() { 133251881Speter public void heapIterationFractionUpdate(double fractionOfHeapVisited) { 134251881Speter err.print('.'); 135251881Speter } 136251881Speter // This will be called after the iteration is complete 137251881Speter public void heapIterationComplete() { 138251881Speter err.println("done."); 139251881Speter } 140251881Speter }); 141251881Speter } 142251881Speter 143251881Speter try { 144251881Speter analysis.run(); 145251881Speter } catch (Exception e) { 146251881Speter // e.printStackTrace(); 147251881Speter if (verbose) 148251881Speter err.println("liveness analysis may be inaccurate ..."); 149251881Speter } 150251881Speter ReversePtrs liveness = VM.getVM().getRevPtrs(); 151251881Speter 152251881Speter out.println("class_loader\tclasses\tbytes\tparent_loader\talive?\ttype"); 153251881Speter out.println(); 154251881Speter 155251881Speter long numClassLoaders = 1L; 156251881Speter long totalNumClasses = bootstrapLoaderData.numClasses; 157251881Speter long totalClassSize = bootstrapLoaderData.classSize; 158251881Speter long numAliveLoaders = 1L; 159251881Speter long numDeadLoaders = 0L; 160251881Speter 161251881Speter // print bootstrap loader details 162251881Speter out.print("<bootstrap>"); 163251881Speter out.print('\t'); 164251881Speter out.print(bootstrapLoaderData.numClasses); 165251881Speter out.print('\t'); 166251881Speter out.print(bootstrapLoaderData.classSize); 167251881Speter out.print('\t'); 168251881Speter out.print(" null "); 169251881Speter out.print('\t'); 170251881Speter // bootstrap loader is always alive 171251881Speter out.print("live"); 172251881Speter out.print('\t'); 173251881Speter out.println("<internal>"); 174251881Speter 175251881Speter for (Iterator keyItr = loaderMap.keySet().iterator(); keyItr.hasNext();) { 176251881Speter Oop loader = (Oop) keyItr.next(); 177251881Speter LoaderData data = (LoaderData) loaderMap.get(loader); 178251881Speter numClassLoaders ++; 179251881Speter totalNumClasses += data.numClasses; 180251881Speter totalClassSize += data.classSize; 181251881Speter 182251881Speter out.print(loader.getHandle()); 183251881Speter out.print('\t'); 184251881Speter out.print(data.numClasses); 185251881Speter out.print('\t'); 186251881Speter out.print(data.classSize); 187251881Speter out.print('\t'); 188251881Speter 189251881Speter class ParentFinder extends DefaultOopVisitor { 190251881Speter public void doOop(OopField field, boolean isVMField) { 191251881Speter if (field.getID().getName().equals("parent")) { 192251881Speter parent = field.getValue(getObj()); 193251881Speter } 194251881Speter } 195251881Speter private Oop parent = null; 196251881Speter public Oop getParent() { return parent; } 197251881Speter } 198251881Speter 199251881Speter ParentFinder parentFinder = new ParentFinder(); 200251881Speter loader.iterate(parentFinder, false); 201251881Speter Oop parent = parentFinder.getParent(); 202251881Speter out.print((parent != null)? parent.getHandle().toString() : " null "); 203251881Speter out.print('\t'); 204251881Speter boolean alive = (liveness != null) ? (liveness.get(loader) != null) : true; 205251881Speter out.print(alive? "live" : "dead"); 206251881Speter if (alive) numAliveLoaders++; else numDeadLoaders++; 207251881Speter out.print('\t'); 208251881Speter Klass loaderKlass = loader.getKlass(); 209251881Speter if (loaderKlass != null) { 210251881Speter out.print(loaderKlass.getName().asString()); 211251881Speter out.print('@'); 212251881Speter out.print(loader.getKlass().getAddress()); 213251881Speter } else { 214251881Speter out.print(" null! "); 215251881Speter } 216251881Speter out.println(); 217251881Speter } 218251881Speter 219251881Speter out.println(); 220251881Speter // summary line 221251881Speter out.print("total = "); 222251881Speter out.print(numClassLoaders); 223251881Speter out.print('\t'); 224251881Speter out.print(totalNumClasses); 225251881Speter out.print('\t'); 226251881Speter out.print(totalClassSize); 227251881Speter out.print('\t'); 228251881Speter out.print(" N/A "); 229251881Speter out.print('\t'); 230251881Speter out.print("alive="); 231251881Speter out.print(numAliveLoaders); 232251881Speter out.print(", dead="); 233251881Speter out.print(numDeadLoaders); 234251881Speter out.print('\t'); 235251881Speter out.print(" N/A "); 236251881Speter out.println(); 237251881Speter } 238251881Speter 239251881Speter private static long objectSize(Oop oop) { 240251881Speter return oop == null ? 0L : oop.getObjectSize(); 241251881Speter } 242251881Speter 243251881Speter // Don't count the shared empty arrays 244251881Speter private static long arraySize(GenericArray arr) { 245251881Speter return arr.getLength() != 0L ? arr.getSize() : 0L; 246251881Speter } 247251881Speter 248251881Speter private long computeSize(InstanceKlass k) { 249251881Speter long size = 0L; 250251881Speter // the InstanceKlass object itself 251251881Speter size += k.getSize(); 252251881Speter 253251881Speter // Constant pool 254251881Speter ConstantPool cp = k.getConstants(); 255251881Speter size += cp.getSize(); 256251881Speter if (cp.getCache() != null) { 257251881Speter size += cp.getCache().getSize(); 258251881Speter } 259251881Speter size += arraySize(cp.getTags()); 260251881Speter 261251881Speter // Interfaces 262251881Speter size += arraySize(k.getLocalInterfaces()); 263251881Speter size += arraySize(k.getTransitiveInterfaces()); 264251881Speter 265251881Speter // Inner classes 266251881Speter size += arraySize(k.getInnerClasses()); 267251881Speter 268251881Speter // Fields 269251881Speter size += arraySize(k.getFields()); 270251881Speter 271251881Speter // Methods 272251881Speter MethodArray methods = k.getMethods(); 273251881Speter int nmethods = (int) methods.getLength(); 274251881Speter if (nmethods != 0L) { 275251881Speter size += methods.getSize(); 276251881Speter for (int i = 0; i < nmethods; ++i) { 277251881Speter Method m = methods.at(i); 278251881Speter size += m.getSize(); 279251881Speter size += m.getConstMethod().getSize(); 280251881Speter } 281251881Speter } 282251881Speter 283251881Speter return size; 284251881Speter } 285251881Speter} 286251881Speter