Heap Sizing
Whichever collector you choose to meet the performance demands of your application, the good news is the JVM will automatically size the heap for you, based on the type of collector and the system or container resources available. However, when the initial sizing does not meet your defined performance goals or the limits of your system (host) or container, your application may need a different heap size configuration.
Sizing the heap can be as simple as increasing or reducing the overall
heap size with the options -Xms and -Xmx (minimum/initial and
maximum heap size, respectively), or it can require adjusting the sizes
of the individual generations or G1 regions. Before resizing the heap,
you need an understanding of:
- Your application’s heap memory needs
- Your host’s and/or container’s memory capacity and configuration
- How your garbage collector manages the heap
Understanding the application’s heap memory needs means understanding its object allocation behaviors, such as peak loads, the length of time most objects tend to live, the amount of memory needed for very large and/or long-lived objects, etc.
For example, for some applications, 99% of the objects are very short-lived and die in the Young Generation, in which case, a large Young Generation size may perform best. Other applications may allocate several very large buffers or other large objects that will have to be allocated directly to the Old Generation, and the sizing of the Old Generation may need to be increased to account for these large objects, or, in the case of G1, the region size may need to be increased to avoid humongous allocations.
We recommend using Java Flight Recorder (JFR) with Heap Statistics enabled and detailed GC logging to get this information. (Poonam Parhar’s Understanding G1GC Logs is a good introduction to reading GC logs.) You will want to run tests in a production-equivalent test environment with production-like loads. In this test environment, record and/or log the application’s object allocation and deallocation behaviors over time, through multiple cycles of peak and light loads. Then analyze the recordings and logs to understand the application’s heap memory needs.
Heap sizing is not always just about the application’s memory needs. The
system (host) or container may have memory and other resource
configurations or limitations that influence heap sizing decisions. For
example, we know from the HotSpot Virtual Machine Garbage Collection Tuning Guide
that the default maximum heap size for a server class machine is ¼ the
physical memory. Now, consider you desire to run four application server
instances on that machine. You will obviously need to reduce the maximum
heap size in order to avoid running out of memory. Or, consider a
container that is configured for memory stealing. In such a case, you
want to commit your entire heap at application launch by setting Xms
equal to Xmx. Otherwise, you may run out of memory should another
container steal your container’s available memory just before the heap
tries to commit more memory to meet an allocation request.
Finally, a basic understanding of how the collectors manage the heap is necessary for any sizing effort beyond the basic minimum and maximum heap sizing.
All supported HotSpot garbage collectors are generational. Specifically, they have a Young Generation and an Old generation. In general, new objects are allocated to a Young generation, where most will also die and the memory cleared with a Young collection. Long-lived objects are eventually moved or “promoted” from the Young Generation to the Old Generation, where they will die eventually and be cleared with an Old collection. In the case of G1, the generations are logical. Meaning, the heap is divided into regions, and some of those regions belong to the Young Generation and some to the Old Generation. For the other HotSpot collectors, the Young and Old generations are contiguous memory spaces.
However, because of their differences, the collectors manage the heap differently, and therefore, have different sizing considerations. For example, the low-pause collectors generally need a larger heap size than serial or parallel collectors for the same workloads. This is because, in order to achieve the low pause times, the Old Generation is collected while application threads continue to run and allocate more objects on the heap. Meaning, the garbage collector is sharing CPU time with the application threads, so it will take concurrent collectors more time to clear the same amount of memory. Plus, new objects will be allocated concurrently with the collection. Therefore, the Old collection will usually start at 60-80% utilization. In contrast, for serial and parallel collectors, the Old collections occur at about 98% utilization, stopping the application thread(s) and using all available CPUs to quickly collect the heap.
Please see each collector’s section of the HotSpot Tuning Guide for more information on heap sizing.
Further Reading
The HotSpot Virtual Machine Garbage Collection Tuning Guide contains all the information you need for choosing the best garbage collector for your needs. Use the links below to view the guide for your version of the JDK.
Other Resources:
- The java Command man page provides instructions for heap sizing using the
-Xmn,-Xms, and-Xmxoptions. - Java Heap Sizing in a Container: Quickly and Easily on Oracle blogs
Last reviewed on Sat Feb 01 2025 00:00:00 GMT+0000 (Coordinated Universal Time)