1 /* 2 * Copyright (c) 2003, 2013, 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 java.io.*; 28 import java.util.*; 29 30 import sun.jvm.hotspot.debugger.*; 31 import sun.jvm.hotspot.memory.*; 32 import sun.jvm.hotspot.oops.*; 33 import sun.jvm.hotspot.runtime.*; 34 import sun.jvm.hotspot.utilities.*; 35 36 /** 37 A command line tool to print class loader statistics. 38 */ 39 40 public class ClassLoaderStats extends Tool { 41 boolean verbose = true; 42 43 public ClassLoaderStats() { 44 super(); 45 } 46 47 public ClassLoaderStats(JVMDebugger d) { 48 super(d); 49 } 50 51 @Override 52 public String getName() { 53 return "classLoaderStats"; 54 } 55 56 public static void main(String[] args) { 57 ClassLoaderStats cls = new ClassLoaderStats(); 58 cls.execute(args); 59 } 60 61 private static class ClassData { 62 Klass klass; 63 long size; 64 65 ClassData(Klass klass, long size) { 66 this.klass = klass; this.size = size; 67 } 68 } 69 70 private static class LoaderData { 71 long numClasses; 72 long classSize; 73 List classDetail = new ArrayList(); // List<ClassData> 74 } 75 76 public void run() { 77 printClassLoaderStatistics(); 78 } 79 80 private void printClassLoaderStatistics() { 81 final PrintStream out = System.out; 82 final PrintStream err = System.err; 83 final Map loaderMap = new HashMap(); 84 // loader data for bootstrap class loader 85 final LoaderData bootstrapLoaderData = new LoaderData(); 86 if (verbose) { 87 err.print("finding class loader instances .."); 88 } 89 90 VM vm = VM.getVM(); 91 ObjectHeap heap = vm.getObjectHeap(); 92 Klass classLoaderKlass = vm.getSystemDictionary().getClassLoaderKlass(); 93 try { 94 heap.iterateObjectsOfKlass(new DefaultHeapVisitor() { 95 public boolean doObj(Oop oop) { 96 loaderMap.put(oop, new LoaderData()); 97 return false; 98 } 99 }, classLoaderKlass); 100 } catch (Exception se) { 101 se.printStackTrace(); 102 } 103 104 if (verbose) { 105 err.println("done."); 106 err.print("computing per loader stat .."); 107 } 108 109 SystemDictionary dict = VM.getVM().getSystemDictionary(); 110 dict.classesDo(new SystemDictionary.ClassVisitor() { 111 public void visit(Klass k) { 112 if (! (k instanceof InstanceKlass)) { 113 return; 114 } 115 Oop loader = ((InstanceKlass) k).getClassLoader(); 116 LoaderData ld = (loader != null) ? (LoaderData)loaderMap.get(loader) 117 : bootstrapLoaderData; 118 if (ld != null) { 119 ld.numClasses++; 120 long size = computeSize((InstanceKlass)k); 121 ld.classDetail.add(new ClassData(k, size)); 122 ld.classSize += size; 123 } 124 } 125 }); 126 127 if (verbose) { 128 err.println("done."); 129 err.print("please wait.. computing liveness"); 130 } 131 132 // compute reverse pointer analysis (takes long time for larger app) 133 ReversePtrsAnalysis analysis = new ReversePtrsAnalysis(); 134 135 if (verbose) { 136 analysis.setHeapProgressThunk(new HeapProgressThunk() { 137 public void heapIterationFractionUpdate(double fractionOfHeapVisited) { 138 err.print('.'); 139 } 140 // This will be called after the iteration is complete 141 public void heapIterationComplete() { 142 err.println("done."); 143 } 144 }); 145 } 146 147 try { 148 analysis.run(); 149 } catch (Exception e) { 150 // e.printStackTrace(); 151 if (verbose) 152 err.println("liveness analysis may be inaccurate ..."); 153 } 154 ReversePtrs liveness = VM.getVM().getRevPtrs(); 155 156 out.println("class_loader\tclasses\tbytes\tparent_loader\talive?\ttype"); 157 out.println(); 158 159 long numClassLoaders = 1L; 160 long totalNumClasses = bootstrapLoaderData.numClasses; 161 long totalClassSize = bootstrapLoaderData.classSize; 162 long numAliveLoaders = 1L; 163 long numDeadLoaders = 0L; 164 165 // print bootstrap loader details 166 out.print("<bootstrap>"); 167 out.print('\t'); 168 out.print(bootstrapLoaderData.numClasses); 169 out.print('\t'); 170 out.print(bootstrapLoaderData.classSize); 171 out.print('\t'); 172 out.print(" null "); 173 out.print('\t'); 174 // bootstrap loader is always alive 175 out.print("live"); 176 out.print('\t'); 177 out.println("<internal>"); 178 179 for (Iterator keyItr = loaderMap.keySet().iterator(); keyItr.hasNext();) { 180 Oop loader = (Oop) keyItr.next(); 181 LoaderData data = (LoaderData) loaderMap.get(loader); 182 numClassLoaders ++; 183 totalNumClasses += data.numClasses; 184 totalClassSize += data.classSize; 185 186 out.print(loader.getHandle()); 187 out.print('\t'); 188 out.print(data.numClasses); 189 out.print('\t'); 190 out.print(data.classSize); 191 out.print('\t'); 192 193 class ParentFinder extends DefaultOopVisitor { 194 public void doOop(OopField field, boolean isVMField) { 195 if (field.getID().getName().equals("parent")) { 196 parent = field.getValue(getObj()); 197 } 198 } 199 private Oop parent = null; 200 public Oop getParent() { return parent; } 201 } 202 203 ParentFinder parentFinder = new ParentFinder(); 204 loader.iterate(parentFinder, false); 205 Oop parent = parentFinder.getParent(); 206 out.print((parent != null)? parent.getHandle().toString() : " null "); 207 out.print('\t'); 208 boolean alive = (liveness != null) ? (liveness.get(loader) != null) : true; 209 out.print(alive? "live" : "dead"); 210 if (alive) numAliveLoaders++; else numDeadLoaders++; 211 out.print('\t'); 212 Klass loaderKlass = loader.getKlass(); 213 if (loaderKlass != null) { 214 out.print(loaderKlass.getName().asString()); 215 out.print('@'); 216 out.print(loader.getKlass().getAddress()); 217 } else { 218 out.print(" null! "); 219 } 220 out.println(); 221 } 222 223 out.println(); 224 // summary line 225 out.print("total = "); 226 out.print(numClassLoaders); 227 out.print('\t'); 228 out.print(totalNumClasses); 229 out.print('\t'); 230 out.print(totalClassSize); 231 out.print('\t'); 232 out.print(" N/A "); 233 out.print('\t'); 234 out.print("alive="); 235 out.print(numAliveLoaders); 236 out.print(", dead="); 237 out.print(numDeadLoaders); 238 out.print('\t'); 239 out.print(" N/A "); 240 out.println(); 241 } 242 243 private static long objectSize(Oop oop) { 244 return oop == null ? 0L : oop.getObjectSize(); 245 } 246 247 // Don't count the shared empty arrays 248 private static long arraySize(GenericArray arr) { 249 return arr.getLength() != 0L ? arr.getSize() : 0L; 250 } 251 252 private long computeSize(InstanceKlass k) { 253 long size = 0L; 254 // the InstanceKlass object itself 255 size += k.getSize(); 256 257 // Constant pool 258 ConstantPool cp = k.getConstants(); 259 size += cp.getSize(); 260 if (cp.getCache() != null) { 261 size += cp.getCache().getSize(); 262 } 263 size += arraySize(cp.getTags()); 264 265 // Interfaces 266 size += arraySize(k.getLocalInterfaces()); 267 size += arraySize(k.getTransitiveInterfaces()); 268 269 // Inner classes 270 size += arraySize(k.getInnerClasses()); 271 272 // Fields 273 size += arraySize(k.getFields()); 274 275 // Methods 276 MethodArray methods = k.getMethods(); 277 int nmethods = (int) methods.getLength(); 278 if (nmethods != 0L) { 279 size += methods.getSize(); 280 for (int i = 0; i < nmethods; ++i) { 281 Method m = methods.at(i); 282 size += m.getSize(); 283 size += m.getConstMethod().getSize(); 284 } 285 } 286 287 return size; 288 } 289 }