≡ Menu

How to monior Heap usage of a Java Application ?

Heap is the memory space where java application objects are stored. Unfortunately the size of Heap is limited (by the -Xmx java command line option). When all of heap is used up, you are in deep trouble. So, it helps to understand how to measure Java heap usage, and that’s exactly what I’m going to be discussing with you in this post.

Very surprisingly, measuring heap is not that straight forward in java world. I believe it is due to the fact there are numerous ways to measure java heap. Oracle seems to introduce new tools with every release (and retire the old ones). For this reason, I recommend everyone to invest in a commercial grade APM (Application Performance Management) tool. With APM tool, you will simply login to the APM interface (typically a web application) to view the JVM heap usage (along with tons of other useful metrics)

Using the command jcmd to measure heap usage

Java comes with a command line tool named jcmd. It should be available in most flavors of Java (Oracle, IBM etc). I’m going to recommend jcmd to measure your heap usage. One of the advantages of using jcmd is the class histogram which not only shows the heap usage but it breaks down the usage by class. This gives you an instant view of what is causing heap to fill up.

Important Note: jcmd does have some impact on the jvm. But I assure it is worth the price, as the details shown by jcmd are very valuable.

Important Note: the command jcmd must be run as the same user (or effective user) as the user running the java application

Let us see jcmd in action.

I’m using Java 1.8 for this excercise. I’m running a java application in my system named test. It is a simple java program (named test.java) that sleeps for 5 minutes.

Simply invoking jcmd without any options shows the available java processes. In the example below, test is my application. sun.tools.jcmd.JCmd is jcmd itself.

~$jcmd
58161 test
58165 sun.tools.jcmd.JCmd

Print all available commands for a given java application

~$jcmd test help
58161:
The following commands are available:
JFR.stop
JFR.start
JFR.dump
JFR.check
VM.native_memory
VM.check_commercial_features
VM.unlock_commercial_features
ManagementAgent.stop
ManagementAgent.start_local
ManagementAgent.start
GC.rotate_log
Thread.print
GC.class_stats
GC.class_histogram
GC.heap_dump
GC.run_finalization
GC.run
VM.uptime
VM.flags
VM.system_properties
VM.command_line
VM.version
help

For more information about a specific command use 'help <command>'.

Note: You can specify either the process id (pid) or the main class name of the java application in place of the first parameter to the jcmd command. The syntax of jcmd is jcmd <process id|main class name> <command>.

For measuring the heap usage, you use the command ‘GC.class_histogram’.

~$jcmd test GC.class_histogram
58161:

num #instances #bytes class name
----------------------------------------------
 1: 1020 93864 [C
 2: 481 54856 java.lang.Class
 3: 526 26072 [Ljava.lang.Object;
 4: 13 25664 [B
 5: 1008 24192 java.lang.String
 6: 79 5688 java.lang.reflect.Field
 7: 256 4096 java.lang.Integer
 8: 94 3760 java.lang.ref.SoftReference
 9: 91 3712 [I
 10: 111 3552 java.util.Hashtable$Entry
 11: 8 3008 java.lang.Thread
 12: 60 2200 [Ljava.lang.String;
 13: 38 1824 sun.util.locale.LocaleObjectCache$CacheEntry
 14: 53 1696 java.util.concurrent.ConcurrentHashMap$Node
 15: 23 1472 java.net.URL
 16: 14 1120 java.lang.reflect.Constructor
 17: 35 1120 java.util.HashMap$Node

...

...

189: 1 16 sun.misc.Unsafe
 190: 1 16 sun.net.www.protocol.file.Handler
 191: 1 16 sun.reflect.ReflectionFactory
Total 4546 283608

In the above output, first column is the serial number, second column is the number of instances, third column is the size in bytes and fourth column is the class name. The last line shows the total. So, there are 4546 instances occupying ~280KB memory.

Now, let’s say I have written some damaging code that creates an integer array of 100,000,000 integers.

System.out.println("I'm creating an array of first 1000000 odd numbers...");
 int odd_nums[] = new int[100000000];
 int k = 1;
 for(int i =0;i<100000000;i++)
 {
 odd_nums[i] = k;
 k = k + 2;
 }

In java each integer takes up 4 bytes. 100,000,000 integers approximately take up 400MB. Once I run the above code, let’s see how much memory is eaten by my application

/$jcmd test GC.class_histogram
58619:

num #instances #bytes class name
----------------------------------------------
 1: 91 400003584 [I
 2: 1018 93544 [C
 3: 481 54856 java.lang.Class
 4: 524 25896 [Ljava.lang.Object;
 5: 10 25024 [B
 6: 1006 24144 java.lang.String
 7: 79 5688 java.lang.reflect.Field
 8: 256 4096 java.lang.Integer
 9: 94 3760 java.lang.ref.SoftReference

...

...

178: 1 16 java.util.concurrent.atomic.AtomicBoolean
 179: 1 16 java.util.jar.JavaUtilJarAccessImpl
 180: 1 16 java.util.zip.ZipFile$1
 181: 1 16 sun.misc.Launcher
 182: 1 16 sun.misc.Launcher$Factory
 183: 1 16 sun.misc.Perf
 184: 1 16 sun.misc.Unsafe
 185: 1 16 sun.net.www.protocol.file.Handler
 186: 1 16 sun.reflect.ReflectionFactory
Total 4514 400281400

As you can see, the heap usage is around 400MB. And the output clearly shows the primitive integer type is taking up all the memory.

Note that jcmd is just one of the many ways you can get the heap utilization info. Here are some more methods

  • Verbose GC logs
  • Visual VM
  • Jconsole
  • Jmap
  • From Java Heap dump

So, now you know how to measure heap usage of your java application. jcmd is an easy and effective tool to quickly retrieve the heap usage and top classes eating up Heap. While there is some impact to the JVM, jcmd is worth the try while troubleshooting memory issues.

PS: I have an interesting article titled 5 not so easy ways to monitor the Heap Usage of your Java Application. Check it out.

 

 

{ 0 comments… add one }

Leave a Comment