The Secrets of Heap Sizing
Noora Peura's Blog |
October 3, 2007 8:04 AM
|
Comments (1)
"How big should I make the Java heap?"
That is a question I get quite often from friends who develop Java applications and hear that I work with a JVM. It is a simple question, but surprisingly tricky to answer. The simple answer is: it depends on your application and your machine. Most people don't like that answer, so here's the long version instead.
Usually a larger heap is better. Larger heaps mean fewer garbage collections, and fewer garbage collections is good. Unfortunately it is not quite as simple as that. There are some additional limitations to consider when selecting a heap size.
A part of the garbage collection time depends on the heap size. The time difference isn't that large - doubling the heap size won't double the garbage collection times, but a garbage collection of a 32 GB heap will take noticeably longer than a garbage collection of a 32 MB heap. Usually the extra overhead in garbage collection times is smaller than the gains from a lower garbage collection frequency, but if your application is very sensitive to long garbage collection pauses you may have to keep down the heap size a bit.
To view the garbage collection pause times you can add -Xverbose:gcpause to the command line. This makes BEA JRockit print out pause time data for each garbage collection. Another way is to do a JRA recording, see the BEA JRockit Mission Control documentation at http://edocs.bea.com/jrockit/tools/index.html for more information.
The amount of physical memory in the machine is a more serious limit. If the heap size is larger than the amount of free physical memory, a part of the heap will be paged to disk (swapping). Accessing the part that is on disk becomes very slow. A garbage collection will access all parts of the heap, so if the heap is on disk a garbage collection may take very long time (I once saw a log from a 20 minute garbage collection!).
So, you have 2 GB memory in your machine and set the heap to 1.9 GB, why does the JVM still start swapping during garbage collection? First of all, the heap isn't all the memory that the JVM requires. The JVM needs memory for Java methods, thread stacks, JNI code, the JVM itself and a lot of internal data structures. Depending on the application this could mean tens or even hundreds of megabytes. Second, the JVM is usually not the only application running on the machine. At least you have an operating system, which also requires memory, and sometimes you have other applications running as well. A more reasonable heap size on a 2 GB machine would thus be somewhere around 1 GB.
BEA JRockit can actually tell you if it is suffering from page faults during garbage collection. If you turn on verbose memory outputs on "debug" level (add -Xverbose:memdbg to the Java command line), you will get an output at each garbage collection telling you how many page faults there were during the garbage collection. If the number of page faults is high throughout the run you may want to reduce the heap size.
But what do you do if you're running in a development environment with a limited amount of memory available and want to set the heap as small as possible? Well, first of all you must decide how small "as small as possible" really is.
You can easily assess the absolute minimum heap requirements of your application with a test run, if you have some realistic high load test scenario that you can simulate. Start the JVM with a large fixed heap, for example -Xms:2g -Xmx:2g if there's enough RAM in the machine, and the command line options -Xgc:parallel and -XXfullCompaction. This makes each garbage collection free as much memory as possible even if it takes some time. Then you can monitor the heap occupancy after each garbage collection using BEA JRockit Mission Control. When you have started your Java application (running on BEA JRockit of course) you start up Mission Control and connect a Console to your application. In the Overview tab you will by default see the Java heap usage in the upper graph. The heap usage should look something like a saw-tooth pattern, going up and up until it reaches 100% and then drop down to a value below 100%. These "drops" are caused by garbage collection. Check the percentage at the bottom of each "drop". This is how much of your Java heap is occupied by live objects. Say for example that 25% of a 2 GB heap is occupied after each garbage collection, which means that you have 0.5 GB of live objects. A simple rule-of-thumb minimum heap size is twice this size.
There you have the limits: twice the size of your live data up to as much as your system can tolerate without paging. Usually larger is better, but if the garbage collection pause times grow too long you may want to trim the heap size a bit. I can't give you a much better answer than that, but hopefully it will at least help you get started.
Comments
Comments are listed in date ascending order (oldest first) | Post Comment
-
Very nice tips. Thanks for sharing this.
Posted by: caiwenliang on October 17, 2007 at 5:10 AM
|