Proposal: Dumping of Extended Class Size Statistics v0.2 - 2013/01/01 Ioi Lam (ioi.lam@oracle.com) Purpose: This is a proposal to provide a simple way for the user to determine the static footprint used by loaded Java classes. This information is useful for analysis in the Density Project. Targeted Version: JDK8, as an diagnostic feature. Scope: All code changes are limited to hotspot/src/share/vm. User Interface: A new diagnostic command "GC.class_stats" is added: jcmd GC.class_stats ... NOTE: initially, the GC.class_stats command is hidden to the user. To use this feature, the JVM must be started with the parameter -XX:+UnlockDiagnosticVMOptions Command options: -csv : Print the output in comma-separated values format. If unspecified, the output is printed as space-indented columns. -help : Print out usage information, as well as the names and meanings of all columns -all : Print out all columns. : A comma-separated list of columns to be printed (see "Definition of Data Columns" section below.) Selection of Data Columns: The data columns printed by the GC.class_stats command are selected by the following procedure: [1] If the -all option is given, all available columns are printed. E.g., jcmd 12345 GC.class_stats -all [2] Otherwise, if the optional arguments are given, only those columns are printed jcmd 12345 GC.class_stats InstSize,InstBytes,Mirror [3] Otherwise, a group of predetermined "usually interesting" columns are printed. Currently, they are: KlassBytes,CpAll,annotations,MethodCount,Bytecodes,MethodAll,ROAll,RWAll,Total Definition of Data Columns: The data columns (names and meanings) are defined in the following table #define HEAP_INSPECTION_COLUMNS_DO(f) \ f(InstSize, "Size of each object instance of the Java class") \ f(InstCount, "Number of object instances of the Java class") \ f(InstBytes, "This is usually (InstSize * InstNum). The only exception is " \ "java.lang.Class, whose InstBytes also includes the spaces" \ "used to store static fields") \ f(Mirror, "Size of the Klass::java_mirror() object") \ f(KlassBytes, "Size of the InstanceKlass or ArrayKlass for this class. " \ "Note that this includes VTab, ITab, OopMap") \ f(K_secondary_supers,"Number of bytes used by the Klass::secondary_supers() array") \ f(VTab, "Size of the embedded vtable in InstanceKlass") \ f(ITab, "Size of the embedded itable in InstanceKlass") \ f(OopMap, "Size of the embedded nonstatic_oop_map in InstanceKlass") \ f(IK_methods, "Number of bytes used by the InstanceKlass::methods() array") \ f(IK_method_ordering, "Number of bytes used by the InstanceKlass::method_ordering() array") \ f(IK_local_interfaces, "Number of bytes used by the InstanceKlass::local_interfaces() array") \ f(IK_transitive_interfaces, "Number of bytes used by the InstanceKlass::transitive_interfaces() array") \ f(IK_fields, "Number of bytes used by the InstanceKlass::fields() array") \ f(IK_inner_classes, "Number of bytes used by the InstanceKlass::inner_classes() array") \ f(IK_signers, "Number of bytes used by the InstanceKlass::singers() array") \ f(annotations, "Size of all annotations") \ f(class_annotations, "Size of class annotations") \ f(fields_annotations,"Size of field annotations") \ f(methods_annotations, "Size of method annotations") \ f(methods_parameter_annotations, "Size of method parameter annotations") \ f(methods_default_annotations, "Size of methods default annotations") \ f(Cp, "Size of InstanceKlass::constants()") \ f(CpTags, "Size of InstanceKlass::constants()->tags()") \ f(CpCache, "Size of InstanceKlass::constants()->cache()") \ f(CpOperands, "Size of InstanceKlass::constants()->operands()") \ f(CpAll, "Sum of Cp + CpTags + CpCache + CpOperands") \ f(MethodCount, "Number of methods in this class") \ f(MethodBytes, "Size of the Method object") \ f(Constmethod, "Size of the ConstMethod object") \ f(Methoddata, "Size of the MethodData object") \ f(Stackmap, "Size of the stackmap_data") \ f(Bytecodes, "Of the \"MethodBytes\" column, how much are the space taken up by bytecodes") \ f(MethodAll, "Sum of MethodBytes + Constmethod + Stackmap + Methoddata") \ f(ROAll, "Size of all class meta data that could (potentially) be placed " \ "in read-only memory. (This could change with CDS design)") \ f(RWAll, "Size of all class meta data that must be placed in read/write " \ "memory. (This could change with CDS design) ") \ f(Total, "ROAll + RWAll") Example output when running HelloWorld: ------------------------------------------------------------------------------ Index Super KlassBytes annotations CpAll MethodCount Bytecodes MethodAll ROAll RWAll Total ClassName 1 -1 528 0 0 0 0 0 0 0 0 [C 2 29 648 2896 17672 118 4331 29536 18488 34040 52528 java.lang.Class 3 -1 528 0 0 0 0 0 0 0 0 [B ... ... 396 29 592 232 1592 7 247 1760 1224 3208 4432 sun.util.locale.LocaleObjectCache 397 29 544 544 1680 20 737 4960 3112 4912 8024 sun.util.locale.LocaleUtils 260488 153808 780656 5437 193450 1346168 879968 1768400 2648368 9.8% 5.8% 29.5% 0.2% 7.3% 50.8% 33.2% 66.8% 100.0% Index Super KlassBytes annotations CpAll MethodCount Bytecodes MethodAll ROAll RWAll Total ClassName ------------------------------------------------------------------------------ Notes: [1] The names of the columns are printed once again at the end of the output for easy human readability. [2] The last two rows of values are the total number of bytes of each column, and the percentage of each column in the grand total, respectively. [3] In this example, all class data take up a grand total of 2,648,368 bytes. [4] In addition to the columns described above, there are two additional columns. These two columns are always printed. Index: A unique serial number assigned to this class. Super: This is the Index of class S, where S is the super class of C. -1 for array classes or java.lang.Object. Sharing of Data Fields Currently, empty arrays are shared by all Klasses. We don't count the size of such empty arrays. In the future, the VM may support more sharing. E.g., + If two Klasses implement the same set of local interfaces, the same local_interfaces() array is shared. + multiple classes may share the same constant pool When this happens, we will need to divide up the size of a shared object proportionally among its owners.