hotspot/agent/src/share/classes/sun/jvm/hotspot/tools/PermStat.java
changeset 16134 ae22dda24476
parent 16133 f54166ffd8d8
parent 15839 3fa21fbf9be7
child 16135 92bf3c68c503
child 16516 a7664cdfc348
equal deleted inserted replaced
16133:f54166ffd8d8 16134:ae22dda24476
     1 /*
       
     2  * Copyright (c) 2003, 2012, 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 perm. generation statistics.
       
    39 */
       
    40 
       
    41 public class PermStat extends Tool {
       
    42    boolean verbose = true;
       
    43 
       
    44    public static void main(String[] args) {
       
    45       PermStat ps = new PermStat();
       
    46       ps.start(args);
       
    47       ps.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 }