Julio Jimenez
Essential DevOps

Essential DevOps

Java Heap Monitoring

Java Heap Monitoring

Julio Jimenez's photo
Julio Jimenez
·Nov 4, 2021·

2 min read

Subscribe to my newsletter and never miss my upcoming articles

Just so y'all know, I'm not a Java guy. But in DevOps, you're sometimes asked to do some weird stuff.

We were asked to assist in diagnosing a java.lang.OutOfMemoryError error being thrown by a COTS file transfer service hosted in our environment. The web app is a Tomcat/Catalina "thing".

Initially, the starting and maximum memory allocations were set to -Xms8G and -Xmx8G, respectively. This, however, was easily exhausted during the early morning hours, when most file transfer jobs were scheduled.

We increased the allocation to -Xms12G -Xmx12G and that did the trick. But how would one measure instantaneous heap consumption?


The answer we found for this question was a tool included in the JDK named jstat.

The jstat command displays performance statistics for an instrumented Java HotSpot VM. The target JVM is identified by its virtual machine identifier, or vmid option.

To be honest, the linked manual page flew right over my head. But with the help of Stack Overflow, I was able to make some sense out of all the numbers.

sudo jstat -gc \
`ps aux | grep java | grep -v grep | awk {'print $2'}` \
1000 3 | \
awk {'print ($1+$2+$6+$8)/1000000'}

I split the above command into four lines for readability. Let's go over each one...

sudo jstat -gc - Run jstat as root with the gc option. Garbage collection is my best guess for what gc stands for.

ps aux | grep java | grep -v grep | awk {'print $2'} - The next expected parameter is the java pid.

1000 3 - In one second (1000ms) we ask jstat to provide us with 3 samples of GC metrics.

awk {'print ($1+$2+$6+$8)/1000000'} - Let's pipe the results to awk and add the S0U, S1U, EU, and OU metrics; then divide it by 1,000,000 to convert the result from kilobytes (KB) to gigabytes (GB).


Make sure the awk field variables ($1, $2, $6, $8) match the provided metric identifiers (S0U, S1U, EU, OU). Past or future versions of jstat could change the way columns are ordered, just saying.

Here's the command again as a one-liner:

sudo jstat -gc `ps aux | grep java | grep -v grep | awk {'print $2'}` 1000 3 | awk {'print ($1+$2+$6+$8)/1000000'}

That's it. Go be essential.

Share this