One of the deadliest errors you can encounter in your Java application is ‘OutOfMemory’ error. The impact this error can have in your application and your business can be enormous. I have seen organizations spend countless hours struggling to fix this error while continuing to have degraded end-user experience (a sure-fire way to lose credibility). One company was actually restarting their application every three hours just to avoid an ugly hang due to OOM. How sad?
In this article, I would like to point out the most important tuning parameter in your Java application. If you get this wrong, no matter how much tuning you put in, you will end up with an OOM sooner or later. Note that there are tons of tuning parameters available to tune the memory. Most of these may not have any effect at all, and some have game-changing effect. The parameter I’m about to reveal is of later kind and the mother of all parameters. This should be the first parameter you should be analyzing to zero-in.
Without further due, here it is.
The most important JVM memory tuning parameter that affects your application is:
The maximum Heap size a.k.a -Xmx
Why is it important?
The Maximum heap size is the absolute maximum amount of memory JVM can allocate for your application (for creating application objects etc). When the Heap is exhausted and GC (Garbage Collection) can no longer find unused objects to clean up, you are DONE. That’s why it is critical to come up with the optimal value for ‘max heap size’ for your application.
How to correctly determine the maximum heap size ?
The goal of the optimal max heap size is actually really simple.
a. It must never be more than the actual RAM (Physical memory) available in your Server
Each Server (physical or virtual) has definite amount of RAM that is used by all the processes running on that server, including the Operating System. Your ‘max heap size’ should never exceed this amount. Why? After RAM is exhausted, the OS will start using the assigned disk space as SWAP space i.e, it will start moving memory pages in and out of the disk based on the usage of the memory pages. And this is a resource intensive process. As soon as the JVM memory pages falls into Disk swap, the performance will noticeably reduce and you don’t want that.
In fact, your ‘max heap size’ at least 20 % below the physical RAM of the Server (provided there are no other memory hungry applications running on the same server. If there are, consider them also for sizing).
b. Minimize the time that JVM is spending on Garbage Collection
Bigger the heap, the full GC will be longer. But it will occur less frequently.
Smaller the heap, the full GC will be quicker but will occur more frequently.
Even though there are gazillion other Java GC tuning parameter that you can use to tweak this behavior, for the most part, this is the case. Trust me, GC time is no good for the end-user. Almost half of the performance related problems (I may be exaggerating here, but it definitely feels like it) are GC time related.
How to find out how much time is spent on GC ? Crank up your Verbose GC logs and take a peek at it. For more information on how to do this, download my free Ebook 9 Free Java Troubleshooting Tools for Application Support Engineers and Developers
c. Fulfill the memory requirement of your application
This goes without saying. If your application needs 1GB max heap and you have set 128MB max heap, forget about other tuning, your application won’t last few hours with load. With that said, one can write really poor code that just eats up all the memory (for example, retrieving millions of records from database without any paging mechanism and sorting them in memory – bad idea). You can determine the max memory requirement for your application in two different ways. You can go to production without any tuning and increase the max memory size based on the ‘out of memory’ errors you encounter. But one problem with this approach is, by the time you arrive at optimal ‘max heap size’, you may not have any customers using the application. A better approach will be to ‘load test’ your application using free tools like JMeter (or commercial products like LoadRunner) and monitor the Heap utilization and GC times. Tweak the size of the heap based on the load test results and you will be good to to.
A final note about ‘max heap size’. If you are running 32 BIT JVM (I don’t know why you would still be doing this), your ‘max heap size’ can’t exceed 2 GB.
There you have it. While tuning JVM memory,get ‘max heap size’ right first. This is the most important parameter. Make sure it never exceeds the RAM of the Server, minimize the GC time and finally fulfill the memory requirement of your application. OOMs are no fun. But by understanding your application behavior and tuning your JVM Memory parameters based on the behavior, you are all set to create a well-oiled machine that generates revenue – your Java Application.