JDK-8054888 : Runtime: Add Diagnostic Command that prints the class hierarchy
  • Type: Sub-task
  • Component: hotspot
  • Sub-Component: runtime
  • Priority: P4
  • Status: Resolved
  • Resolution: Fixed
  • Submitted: 2014-08-12
  • Updated: 2023-11-06
  • Resolved: 2015-02-14
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 8 JDK 9
8u411Fixed 9 b53Fixed
Related Reports
Relates :  
Relates :  
Description
The runtime team is responsible for implementing the following Diagnostic Commands (see main bug):

print_class_summary
print_utf8pool (We need to check if this is really necessary and what use case it serves)
Comments
URL: http://hg.openjdk.java.net/jdk9/jdk9/hotspot/rev/034eb71ab7fd User: lana Date: 2015-03-04 22:02:39 +0000
04-03-2015

URL: http://hg.openjdk.java.net/jdk9/hs-rt/hotspot/rev/034eb71ab7fd User: jiangli Date: 2015-02-14 00:00:32 +0000
14-02-2015

Sample output from the new VM.class_hierarchy as implemented: $> jcmd NeverExit help VM.class_hierarchy 7836: VM.class_hierarchy Print a list of all loaded classes, indented to show the class hiearchy. The name of each classes is followed by the ClassLoaderData* of its ClassLoader, or "null" if loaded by the bootstrap class loader. Impact: Medium: Depends on number of loaded classes. Syntax : VM.class_hierarchy [options] [<classname>] Arguments: classname : [optional] Name of class whose hierarchy should be printed. If not specified, all class hierarchies are printed. (STRING, no default value) Options: (options must be specified using the <key> or <key>=<value> syntax) -i : [optional] Inherited interfaces should be printed. (BOOLEAN, false) -s : [optional] If a classname is specified, print its subclasses. Otherwise only its superclasses are printed. (BOOLEAN, false) $> jcmd NeverExit VM.class_hierarchy NeverExit -i -s 7836: java.lang.Object/null |--NeverExit/0xa5b37ea0 | implements NE2/0xa5b37ea0 (declared intf) | implements NE1/0xa5b37ea0 (transitive intf) $> jcmd NeverExit VM.class_hierarchy java.lang.Error 7836: java.lang.Object/null |--java.lang.Throwable/null | |--java.lang.Error/null $> jcmd NeverExit VM.class_hierarchy java.lang.Error -i 7836: java.lang.Object/null |--java.lang.Throwable/null | implements java.io.Serializable/null (declared intf) | |--java.lang.Error/null | | implements java.io.Serializable/null (transitive intf) $> jcmd NeverExit VM.class_hierarchy java.lang.Error -s 7836: java.lang.Object/null |--java.lang.Throwable/null | |--java.lang.Error/null | | |--java.lang.VirtualMachineError/null | | | |--java.lang.StackOverflowError/null | | | |--java.lang.OutOfMemoryError/null | | |--java.lang.LinkageError/null | | | |--java.lang.IncompatibleClassChangeError/null | | | | |--java.lang.NoSuchMethodError/null | | | |--java.lang.BootstrapMethodError/null | | | |--java.lang.NoClassDefFoundError/null | | |--java.lang.ThreadDeath/null $> jcmd NeverExit VM.class_hierarchy java.lang.Error -s -i 7836: java.lang.Object/null |--java.lang.Throwable/null | implements java.io.Serializable/null (declared intf) | |--java.lang.Error/null | | implements java.io.Serializable/null (transitive intf) | | |--java.lang.VirtualMachineError/null | | | implements java.io.Serializable/null (transitive intf) | | | |--java.lang.StackOverflowError/null | | | | implements java.io.Serializable/null (transitive intf) | | | |--java.lang.OutOfMemoryError/null | | | | implements java.io.Serializable/null (transitive intf) | | |--java.lang.LinkageError/null | | | implements java.io.Serializable/null (transitive intf) | | | |--java.lang.IncompatibleClassChangeError/null | | | | implements java.io.Serializable/null (transitive intf) | | | | |--java.lang.NoSuchMethodError/null | | | | | implements java.io.Serializable/null (transitive intf) | | | |--java.lang.BootstrapMethodError/null | | | | implements java.io.Serializable/null (transitive intf) | | | |--java.lang.NoClassDefFoundError/null | | | | implements java.io.Serializable/null (transitive intf) | | |--java.lang.ThreadDeath/null | | | implements java.io.Serializable/null (transitive intf)
13-02-2015

I tend to prefer it being done by the VM so the user has a more readily available human readable view of the class hierarchy. As there also seems to be a desire by others to add the "class name" option, this is more to the point of using this dcmd during debug sessions, and in an interactive way. Stick another tool between you and the info you want, and you are less likely to use it, or even know about it.
08-01-2015

So the question is -- should we use the existing output and parse it external to the VM (using a script or a Java program, for example), or do we want to add new code into the VM to produce the class hierarchy. I am in favor of doing it outside of the VM to keep the VM light.
08-01-2015

[~iklam], I didn't see the ClassLoader field in GC.class_stats since it isn't one of the default fields. Good to see it there. I notice however that GC.class_stats and VM.classloader_stats prints ClassLoader IDs in different ways - it would be useful to use the same identifier (filed JDK-8068665).
08-01-2015

Yes, that was already understood. I think serviceability team already has tools that parse the jrockit output, and this new output is similar, so should be easy to convert. Also, it is human readable if that's what you are looking for.
08-01-2015

The output of GC.class_stats can be post-processed (by a script) to generate the class hierarchy. The Super field records the Index of each class's super class. [~sla], the ClassLoader field in GC.class_stats shows the defining class loader instance of each class.
08-01-2015

The above Throwable example got me thinking it might be useful to accept a command line argument with the name of a class to show all subclasses of. Maybe I'll add that as an enhancement at some point.
05-01-2015

Thought the Throwable output would be a nice example: java.lang.Object ... |--java.lang.Throwable | |--java.lang.Exception | | |--java.lang.InterruptedException | | |--java.lang.ReflectiveOperationException | | | |--java.lang.ClassNotFoundException | | |--java.lang.RuntimeException | | | |--java.lang.IllegalMonitorStateException | | | |--java.lang.ArrayStoreException | | | |--java.lang.ClassCastException | | | |--java.lang.ArithmeticException | | | |--java.lang.NullPointerException | | | |--java.lang.IllegalArgumentException | |--java.lang.Error | | |--java.lang.VirtualMachineError | | | |--java.lang.StackOverflowError | | | |--java.lang.OutOfMemoryError | | |--java.lang.LinkageError | | | |--java.lang.IncompatibleClassChangeError | | | | |--java.lang.NoSuchMethodError | | | |--java.lang.BootstrapMethodError | | | |--java.lang.NoClassDefFoundError | | |--java.lang.ThreadDeath
05-01-2015

...and it's more readable with a mono-space font.
22-12-2014

The new dcmd will be called VM.class_summary. It will display the class hierarchy in a way very similar to JRockit. See example output below. It was decided not to try to combine with GC.class_stats because: (1) this would clutter the output even more, and (2) GC.class_stats requires doing a full heap scan to accumulate allocation information, which is not necessary when just displaying the class hierarchy. Output will look as follows: java.lang.Object |--java.security.Guard |--java.lang.ClassLoader$3 |--java.lang.invoke.MethodHandleImpl |--java.lang.StringCoding$StringEncoder |--java.util.concurrent.atomic.AtomicReferenceFieldUpdater$AtomicReferenceFieldUpdaterImpl$1 |--java.lang.CharacterData | |--java.lang.CharacterDataLatin1 |--java.nio.charset.spi.CharsetProvider | |--sun.nio.cs.FastCharsetProvider | | |--sun.nio.cs.StandardCharsets |--java.util.BitSet |--java.lang.Number | |--java.lang.Float | |--java.lang.Long | |--java.util.concurrent.atomic.AtomicLong | |--java.lang.Integer | |--java.util.concurrent.atomic.AtomicInteger | |--java.lang.Short | |--java.lang.Byte | |--java.lang.Double If you follow the '|' down from a class, every class you reach before hitting a break (non '|' character) is a direct or indirect subclass of the class. If you reach a subclass that starts with '|--', then it is a direct subclass.
22-12-2014

print_class_summary in JRockit prints a list of all loaded classes and their inheritance hierarchy. We already have “GC.class_stats”, “GC.class_histogram” and "VM.classloader_stats" which together have some of the information from print_class_summary. GC.class_stats shows the inheritance hierarchy, but the class to class loader mapping is missing. So instead of implementing yet another command, perhaps we an add class loader information to GC.class_stats and GC.class_histogram. That together with with VM.classloader_stats seems to cover most cases and seems pretty powerful. Another worthwhile improvement is to remove the need for -XX:+UnlockDiagnosticVMOptions on GC.class_stats.
17-11-2014

The functionality of print_utf8pool is being implemented as the commands VM.stringtable and VM.symboltable in JDK-8059510.
14-11-2014