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