Programming

Inspect the Contents of the Java Metaspace Region

Spread the love


JVM Memory has the following regions:

  1. Young Generation
  2. Old Generation
  3. Metaspace
  4. Others region

Fig: JVM memory regions

                                                                         Fig: JVM memory regions

To see what objects are stored in what region, you may refer to this video clip. Sometimes your application might run into ‘java.lang.OutOfMemoryError: Metaspace as discussed in this post. In such circumstances, you might want to see what the contents are loaded in the Metaspace region of the JVM. In nutshell, the Metaspace region in the JVM memory contains the class metadata definitions that are required to execute your application. If you want to understand what class metadata definitions mean, you can refer to this documentation. It has intense details, you may not have to understand all the details of it. Basically, if you can understand what are the classes that are loaded into memory, it will give a good idea what are the contents that are present in the Metaspace region of the JVM memory. In this post let’s explore the options that are available to see the classes that are loaded into the Metaspace.

Below are the options to see the classes that are loaded in the Metaspace:

  1. -verbose:class
  2. -Xlog:class+load
  3. jcmd GC.class_histogram
  4. Programmatic approach
  5. Heap Dump analysis

Let’s discuss each option in detail in this post.

1. -Verbose: Class

If you are running on Java version 8 or below then you can use this option. When you pass the -verbose:class option to your application during startup, it will print all the classes that are loaded into memory. Loaded classes will be printed in the standard error stream (i.e. console, if you aren’t routing your error stream to a log file).

java {app_name} -verbose:class

Following is the sample output of the open source BuggyApp program when ‘-verbose:class’ argument is passed:

[Opened C:\Program Files\Java\jre1.8.0_171\lib\rt.jar] 
[Loaded java.lang.Object from C:\Program Files\Java\jre1.8.0_171\lib\rt.jar] 
[Loaded java.io.Serializable from C:\Program Files\Java\jre1.8.0_171\lib\rt.jar] 
[Loaded java.lang.Comparable from C:\Program Files\Java\jre1.8.0_171\lib\rt.jar] 
[Loaded java.lang.CharSequence from C:\Program Files\Java\jre1.8.0_171\lib\rt.jar] 
[Loaded java.lang.String from C:\Program Files\Java\jre1.8.0_171\lib\rt.jar] 
[Loaded java.lang.reflect.AnnotatedElement from C:\Program 
Files\Java\jre1.8.0_171\lib\rt.jar] 
[Loaded java.lang.reflect.GenericDeclaration from C:\Program 
Files\Java\jre1.8.0_171\lib\rt.jar] 
[Loaded java.lang.reflect.Type from C:\Program Files\Java\jre1.8.0_171\lib\rt.jar] 
[Loaded java.lang.Class from C:\Program Files\Java\jre1.8.0_171\lib\rt.jar] 
[Loaded java.lang.Cloneable from C:\Program Files\Java\jre1.8.0_171\lib\rt.jar] 
[Loaded java.lang.ClassLoader from C:\Program Files\Java\jre1.8.0_171\lib\rt.jar] 
[Loaded java.lang.System from C:\Program Files\Java\jre1.8.0_171\lib\rt.jar] 
[Loaded java.lang.Throwable from C:\Program Files\Java\jre1.8.0_171\lib\rt.jar] 
[Loaded java.lang.Error from C:\Program Files\Java\jre1.8.0_171\lib\rt.jar] 
[Loaded java.lang.ThreadDeath from C:\Program Files\Java\jre1.8.0_171\lib\rt.jar] 
[Loaded java.lang.Exception from C:\Program Files\Java\jre1.8.0_171\lib\rt.jar] 
[Loaded java.lang.RuntimeException from C:\Program Files\Java\jre1.8.0_171\lib\rt.jar] 
[Loaded java.lang.SecurityManager from C:\Program Files\Java\jre1.8.0_171\lib\rt.jar] 
[Loaded java.security.ProtectionDomain from C:\Program Files\Java\jre1.8.0_171\lib\rt.jar] 
[Loaded java.security.AccessControlContext from C:\Program 
Files\Java\jre1.8.0_171\lib\rt.jar] 
[Loaded java.security.SecureClassLoader from C:\Program 
Files\Java\jre1.8.0_171\lib\rt.jar] 
[Loaded java.lang.ReflectiveOperationException from C:\Program 
Files\Java\jre1.8.0_171\lib\rt.jar] 
[Loaded java.lang.ClassNotFoundException from C:\Program 
Files\Java\jre1.8.0_171\lib\rt.jar] 
[Loaded java.lang.LinkageError from C:\Program Files\Java\jre1.8.0_171\lib\rt.jar] 
[Loaded java.lang.NoClassDefFoundError from C:\Program Files\Java\jre1.8.0_171\lib\rt.jar] 
[Loaded java.lang.ClassCastException from C:\Program Files\Java\jre1.8.0_171\lib\rt.jar] 
[Loaded java.lang.ArrayStoreException from C:\Program Files\Java\jre1.8.0_171\lib\rt.jar] 
[Loaded java.lang.VirtualMachineError from C:\Program Files\Java\jre1.8.0_171\lib\rt.jar] 
[Loaded java.lang.OutOfMemoryError from C:\Program Files\Java\jre1.8.0_171\lib\rt.jar] 
[Loaded java.lang.StackOverflowError from C:\Program Files\Java\jre1.8.0_171\lib\rt.jar]
 

2. -Xlog:Class+Load

If you are running on Java version 9 or above then you can use this option. When you pass the ‘-Xlog:class+load’ option to your application during startup, it will print all the classes that are loaded into memory. Loaded classes will be printed in the file path you have configured.

java {app_name} -Xlog:class+load=info:/opt/log/loadedClasses.txt

Following is the sample output of a java program when ‘-Xlog:class+load’ argument is passed:

[0.004s][info][class,load] opened: /home/ec2-user/jdk-9.0.4/lib/modules 
[0.006s][info][class,load] java.lang.Object source: jrt:/java.base 
[0.007s][info][class,load] java.io.Serializable source: jrt:/java.base 
[0.007s][info][class,load] java.lang.Comparable source: jrt:/java.base 
[0.007s][info][class,load] java.lang.CharSequence source: jrt:/java.base 
[0.007s][info][class,load] java.lang.String source: jrt:/java.base 
[0.007s][info][class,load] java.lang.reflect.AnnotatedElement source: jrt:/java.base 
[0.007s][info][class,load] java.lang.reflect.GenericDeclaration source: jrt:/java.base 
[0.007s][info][class,load] java.lang.reflect.Type source: jrt:/java.base 
[0.008s][info][class,load] java.lang.Class source: jrt:/java.base 
[0.008s][info][class,load] java.lang.Cloneable source: jrt:/java.base 
[0.008s][info][class,load] java.lang.ClassLoader source: jrt:/java.base 
[0.008s][info][class,load] java.lang.System source: jrt:/java.base 
[0.008s][info][class,load] java.lang.Throwable source: jrt:/java.base 
[0.008s][info][class,load] java.lang.Error source: jrt:/java.base 
[0.008s][info][class,load] java.lang.ThreadDeath source: jrt:/java.base 
[0.008s][info][class,load] java.lang.Exception source: jrt:/java.base 
[0.008s][info][class,load] java.lang.RuntimeException source: jrt:/java.base 
[0.008s][info][class,load] java.lang.SecurityManager source: jrt:/java.base 
[0.008s][info][class,load] java.security.ProtectionDomain source: jrt:/java.base 
[0.009s][info][class,load] java.security.AccessControlContext source: jrt:/java.base 
[0.009s][info][class,load] java.security.SecureClassLoader source: jrt:/java.base 
[0.009s][info][class,load] java.lang.ReflectiveOperationException source: jrt:/java.base 
[0.009s][info][class,load] java.lang.ClassNotFoundException source: jrt:/java.base 
[0.009s][info][class,load] java.lang.LinkageError source: jrt:/java.base 
[0.009s][info][class,load] java.lang.NoClassDefFoundError source: jrt:/java.base 
[0.009s][info][class,load] java.lang.ClassCastException source: jrt:/java.base 
[0.009s][info][class,load] java.lang.ArrayStoreException source: jrt:/java.base 
[0.009s][info][class,load] java.lang.VirtualMachineError source: jrt:/java.base 
[0.009s][info][class,load] java.lang.OutOfMemoryError source: jrt:/java.base 
[0.009s][info][class,load] java.lang.StackOverflowError source: jrt:/java.base 
[0.009s][info][class,load] java.lang.IllegalMonitorStateException source: jrt:/java.base 
[0.009s][info][class,load] java.lang.ref.Reference source: jrt:/java.base 
[0.009s][info][class,load] java.lang.ref.SoftReference source: jrt:/java.base 
[0.009s][info][class,load] java.lang.ref.WeakReference source: jrt:/java.base 
[0.009s][info][class,load] java.lang.ref.FinalReference source: jrt:/java.base 
[0.009s][info][class,load] java.lang.ref.PhantomReference source: jrt:/java.base 
[0.009s][info][class,load] java.lang.ref.Finalizer source: jrt:/java.base 
[0.009s][info][class,load] java.lang.Runnable source: jrt:/java.base 
[0.009s][info][class,load] java.lang.Thread source: jrt:/java.base 
[0.009s][info][class,load] java.lang.Thread$UncaughtExceptionHandler source: 
jrt:/java.base 
[0.009s][info][class,load] java.lang.ThreadGroup source: jrt:/java.base 
[0.010s][info][class,load] java.util.Map source: jrt:/java.base 
[0.010s][info][class,load] java.util.Dictionary source: jrt:/java.base 
[0.010s][info][class,load] java.util.Hashtable source: jrt:/java.base 
[0.010s][info][class,load] java.util.Properties source: jrt:/java.base 
[0.010s][info][class,load] java.lang.Module source: jrt:/java.base 
[0.010s][info][class,load] java.lang.reflect.AccessibleObject source: jrt:/java.base

3. Jcmd Gc.class_histogram

JDK contains a tool called ‘jcmd’. You can invoke this tool when JVM is running to inspect the contents of the Metaspace region. When you invoke this tool with GC.class_histogram argument, it will print the list of classes that are loaded into the memory.  You can invoke this tool in two modes:

A. Print Loaded Classes on the Console

jcmd {pid} GC.class_histogram

When you invoke the ‘jcmd’ as shown above, it will print all the loaded classes in the console. Here {pid} is the process id of your java application. 

B. Print Loaded Classes on a File

jcmd {pid} GC.class_histogram filename={file-path}

When you invoke the ‘jcmd’ as shown above, it will print all the loaded classes in the file path specified in the ‘filename’ argument. Here {pid} is the process id of your java application.

Here is a blog post which helps you to identify the process id quickly.

Following is the sample output of the open source BuggyApp program when ‘jcmd GC.class_histogram’ argument is passed:

jcmd 19684 GC.class_histogram 
19684:  

num     #instances         #bytes  class name 
----------------------------------------------   
1:        143036        75523008  [Ljavassist.bytecode.ConstInfo;   
2:        718060        70032224  [C   
3:       1573553        50353696  java.util.HashMap$Node   
4:        430124        24732832  [Ljava.lang.Object;   
5:       1001290        24030960  javassist.bytecode.Utf8Info   
6:        858268        20598432  java.util.ArrayList   
7:        718037        17232888  java.lang.String   
8:        144011        14987488  java.lang.Class   
9:        143081        11447152  [Ljava.util.HashMap$Node;  
10:        143036        9154304  javassist.bytecode.ClassFile  
11:        143035        9154240  javassist.CtNewClass  
12:        286124        6892400  [B  
13:        143085        6868080  java.util.HashMap  
14:        286078        6865872  javassist.bytecode.ClassInfo  
15:        143036        6865728  [[Ljavassist.bytecode.ConstInfo;  
16:        143049        5721960  javassist.bytecode.MethodInfo  
17:        143042        5721680  javassist.bytecode.CodeAttribute  
18:        143323        4586336  java.util.Hashtable$Entry  
19:        143038        4577216  java.lang.ref.WeakReference  
20:        143036        4577152  javassist.bytecode.ConstPool  
21:        143045        3433080  javassist.bytecode.MethodrefInfo  
22:        143045        3433080  javassist.bytecode.NameAndTypeInfo  
23:        143042        3433008  javassist.bytecode.ExceptionTable  
24:        143036        3432864  javassist.bytecode.LongVector  
25:        143036        3432864  javassist.bytecode.SourceFileAttribute  
26:        143622        2323336  [I  
27:            10         788688  [Ljava.util.Hashtable$Entry;  
28:           642          20544  java.util.concurrent.ConcurrentHashMap$Node  
29:           244          13664  java.lang.invoke.MemberName  
30:           341          10912  sun.misc.FDBigInteger  
31:           212           8480  java.lang.ref.SoftReference  
32:           140           8400  [Ljava.lang.ref.SoftReference;  
33:           234           7488  java.lang.invoke.LambdaForm$Name  
34:           176           7040  java.lang.invoke.MethodType  
35:           256           6144  java.lang.Long  
36:            16           6016  java.lang.Thread  
37:           173           5880  [Ljava.lang.Class;  
38:           366           5856  java.lang.Object  
39:           177           5664  java.lang.invoke.MethodType$ConcurrentWeakInternSet$WeakEntry  
40:            10           5280  [Ljava.util.concurrent.ConcurrentHashMap$Node;  
41:           256           4096  java.lang.Byte  
42:           256           4096  java.lang.Integer  
43:           256           4096  java.lang.Short  
44:            73           4088  java.lang.invoke.MethodTypeForm  
45:            82           3808  [Ljava.lang.invoke.LambdaForm$Name;  
46:            77           3696  java.lang.invoke.LambdaForm

4. Programmatic Approach

You can also use a programmatic approach to print the classes that are loaded into the memory. Open source Guava library provides APIs to print the loaded classes. Below is the code sample that leverages the Guava library to print the loaded classes in the memory:

ClassPath classPath = ClassPath.from(BuggyAppLoader.class.getClassLoader()); 
Set<ClassInfo> classes = classPath.getAllClasses(); 
for(ClassInfo classInfo : classes) {     
     logger.info(classInfo.getName()); 
}

org.apache.catalina.core.AsyncContextImpl 
org.apache.catalina.core.AsyncListenerWrapper 
org.apache.catalina.core.Constants 
org.apache.catalina.core.ContainerBase$ContainerBackgroundProcessor 
org.apache.catalina.core.ContainerBase$PrivilegedAddChild 
org.apache.catalina.core.ContainerBase$StartChild 
org.apache.catalina.core.ContainerBase$StartStopThreadFactory 
org.apache.catalina.core.ContainerBase$StopChild 
org.apache.catalina.core.ContainerBase 
org.apache.catalina.core.DefaultInstanceManager$1 
org.apache.catalina.core.DefaultInstanceManager$2 
org.apache.catalina.core.DefaultInstanceManager$3 
org.apache.catalina.core.DefaultInstanceManager$AnnotationCacheEntry 
org.apache.catalina.core.DefaultInstanceManager$AnnotationCacheEntryType 
org.apache.catalina.core.DefaultInstanceManager 
org.apache.catalina.core.JreMemoryLeakPreventionListener 
org.apache.catalina.core.NamingContextListener 
org.apache.catalina.core.StandardContext$1 
org.apache.catalina.core.StandardContext$ContextFilterMaps 
org.apache.catalina.core.StandardContext$NoPluggabilityServletContext 
org.apache.catalina.core.StandardContext 
org.apache.catalina.core.StandardContextValve 
org.apache.catalina.core.StandardEngine$AccessLogListener 
org.apache.catalina.core.StandardEngine$NoopAccessLog 
org.apache.catalina.core.StandardEngine 
org.apache.catalina.core.StandardEngineValve 
org.apache.catalina.core.StandardHost$1 
org.apache.catalina.core.StandardHost$MemoryLeakTrackingListener 
org.apache.catalina.core.StandardHost 
org.apache.catalina.core.StandardHostValve 
org.apache.catalina.core.StandardPipeline 
org.apache.catalina.core.StandardServer 
org.apache.catalina.core.StandardService 
org.apache.catalina.core.StandardThreadExecutor 
org.apache.catalina.core.StandardWrapper 
org.apache.catalina.core.StandardWrapperFacade 
org.apache.catalina.core.StandardWrapperValve 
org.apache.catalina.core.ThreadLocalLeakPreventionListener

5. Heap Dump Analysis

Another option to see the classes that are loaded into memory is to inspect the Heap Dump. Heap dump reports all the data, objects, and classes that are loaded into memory. You can use one of the approaches given here to capture the heap dump. Once a heap dump is captured, you can use the heap dump analysis tools such as Eclipse MAT, and HeapHero,… to analyze the heap dump.

Below is the excerpt from the report generated by the HeapHero tool that shows the classes that are loaded into the memory.

What's in your memory

Note: All the approaches mentioned above will not add noticeable overhead to your application, however the heap dump approach is an intrusive option and it will add considerable overhead to your application. When heap dump is captured your application will be paused until capturing is complete. 

Video



Source link

Related Articles

Leave a Reply

Your email address will not be published.

Back to top button