Path: blob/master/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/ClassLoaderStats.java
41161 views
/*1* Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*22*/2324package sun.jvm.hotspot.tools;2526import java.io.*;27import java.util.*;2829import sun.jvm.hotspot.debugger.*;30import sun.jvm.hotspot.classfile.*;31import sun.jvm.hotspot.memory.*;32import sun.jvm.hotspot.oops.*;33import sun.jvm.hotspot.runtime.*;34import sun.jvm.hotspot.utilities.*;3536/**37A command line tool to print class loader statistics.38*/3940public class ClassLoaderStats extends Tool {41boolean verbose = true;4243public ClassLoaderStats() {44super();45}4647public ClassLoaderStats(JVMDebugger d) {48super(d);49}5051@Override52public String getName() {53return "classLoaderStats";54}5556public static void main(String[] args) {57ClassLoaderStats cls = new ClassLoaderStats();58cls.execute(args);59}6061private static class ClassData {62Klass klass;63long size;6465ClassData(Klass klass, long size) {66this.klass = klass; this.size = size;67}68}6970private static class LoaderData {71long numClasses;72long classSize;73List<ClassData> classDetail = new ArrayList<>();74}7576public void run() {77printClassLoaderStatistics();78}7980private void printClassLoaderStatistics() {81final PrintStream out = System.out;82final PrintStream err = System.err;83final Map<Oop, LoaderData> loaderMap = new HashMap<>();84// loader data for bootstrap class loader85final LoaderData bootstrapLoaderData = new LoaderData();86if (verbose) {87err.print("finding class loader instances ..");88}8990VM vm = VM.getVM();91ObjectHeap heap = vm.getObjectHeap();92Klass classLoaderKlass = vm.getSystemDictionary().getClassLoaderKlass();93try {94heap.iterateObjectsOfKlass(new DefaultHeapVisitor() {95public boolean doObj(Oop oop) {96loaderMap.put(oop, new LoaderData());97return false;98}99}, classLoaderKlass);100} catch (Exception se) {101se.printStackTrace();102}103104if (verbose) {105err.println("done.");106err.print("computing per loader stat ..");107}108109ClassLoaderDataGraph cldg = VM.getVM().getClassLoaderDataGraph();110cldg.classesDo(new ClassLoaderDataGraph.ClassVisitor() {111public void visit(Klass k) {112if (! (k instanceof InstanceKlass)) {113return;114}115Oop loader = ((InstanceKlass) k).getClassLoader();116LoaderData ld = (loader != null) ? (LoaderData)loaderMap.get(loader)117: bootstrapLoaderData;118if (ld != null) {119ld.numClasses++;120long size = computeSize((InstanceKlass)k);121ld.classDetail.add(new ClassData(k, size));122ld.classSize += size;123}124}125});126127if (verbose) {128err.println("done.");129err.print("please wait.. computing liveness");130}131132// compute reverse pointer analysis (takes long time for larger app)133ReversePtrsAnalysis analysis = new ReversePtrsAnalysis();134135if (verbose) {136analysis.setHeapProgressThunk(new HeapProgressThunk() {137public void heapIterationFractionUpdate(double fractionOfHeapVisited) {138err.print('.');139}140// This will be called after the iteration is complete141public void heapIterationComplete() {142err.println("done.");143}144});145}146147try {148analysis.run();149} catch (Exception e) {150// e.printStackTrace();151if (verbose)152err.println("liveness analysis may be inaccurate ...");153}154ReversePtrs liveness = VM.getVM().getRevPtrs();155156out.println("class_loader\tclasses\tbytes\tparent_loader\talive?\ttype");157out.println();158159long numClassLoaders = 1L;160long totalNumClasses = bootstrapLoaderData.numClasses;161long totalClassSize = bootstrapLoaderData.classSize;162long numAliveLoaders = 1L;163long numDeadLoaders = 0L;164165// print bootstrap loader details166out.print("<bootstrap>");167out.print('\t');168out.print(bootstrapLoaderData.numClasses);169out.print('\t');170out.print(bootstrapLoaderData.classSize);171out.print('\t');172out.print(" null ");173out.print('\t');174// bootstrap loader is always alive175out.print("live");176out.print('\t');177out.println("<internal>");178179for (Iterator keyItr = loaderMap.keySet().iterator(); keyItr.hasNext();) {180Oop loader = (Oop) keyItr.next();181LoaderData data = (LoaderData) loaderMap.get(loader);182numClassLoaders ++;183totalNumClasses += data.numClasses;184totalClassSize += data.classSize;185186out.print(loader.getHandle());187out.print('\t');188out.print(data.numClasses);189out.print('\t');190out.print(data.classSize);191out.print('\t');192193class ParentFinder extends DefaultOopVisitor {194public void doOop(OopField field, boolean isVMField) {195if (field.getID().getName().equals("parent")) {196parent = field.getValue(getObj());197}198}199private Oop parent = null;200public Oop getParent() { return parent; }201}202203ParentFinder parentFinder = new ParentFinder();204loader.iterate(parentFinder, false);205Oop parent = parentFinder.getParent();206out.print((parent != null)? parent.getHandle().toString() : " null ");207out.print('\t');208boolean alive = (liveness != null) ? (liveness.get(loader) != null) : true;209out.print(alive? "live" : "dead");210if (alive) numAliveLoaders++; else numDeadLoaders++;211out.print('\t');212Klass loaderKlass = loader.getKlass();213if (loaderKlass != null) {214out.print(loaderKlass.getName().asString());215out.print('@');216out.print(loader.getKlass().getAddress());217} else {218out.print(" null! ");219}220out.println();221}222223out.println();224// summary line225out.print("total = ");226out.print(numClassLoaders);227out.print('\t');228out.print(totalNumClasses);229out.print('\t');230out.print(totalClassSize);231out.print('\t');232out.print(" N/A ");233out.print('\t');234out.print("alive=");235out.print(numAliveLoaders);236out.print(", dead=");237out.print(numDeadLoaders);238out.print('\t');239out.print(" N/A ");240out.println();241}242243private static long objectSize(Oop oop) {244return oop == null ? 0L : oop.getObjectSize();245}246247// Don't count the shared empty arrays248private static long arraySize(GenericArray arr) {249return arr.getLength() != 0L ? arr.getSize() : 0L;250}251252private long computeSize(InstanceKlass k) {253long size = 0L;254// the InstanceKlass object itself255size += k.getSize();256257// Constant pool258ConstantPool cp = k.getConstants();259size += cp.getSize();260if (cp.getCache() != null) {261size += cp.getCache().getSize();262}263size += arraySize(cp.getTags());264265// Interfaces266size += arraySize(k.getLocalInterfaces());267size += arraySize(k.getTransitiveInterfaces());268269// Inner classes270size += arraySize(k.getInnerClasses());271272// Fields273size += arraySize(k.getFields());274275// Methods276MethodArray methods = k.getMethods();277int nmethods = (int) methods.getLength();278if (nmethods != 0L) {279size += methods.getSize();280for (int i = 0; i < nmethods; ++i) {281Method m = methods.at(i);282size += m.getSize();283size += m.getConstMethod().getSize();284}285}286287return size;288}289}290291292