comparison agent/src/share/classes/sun/jvm/hotspot/tools/ClassLoaderStats.java @ 8112:b685ca4f4fb9

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