ZGC | Using -XX:SoftMaxHeapSize
In JDK 13 we introduced a new JVM option called -XX:SoftMaxHeapSize=<size>
.
ZGC is so far the only garbage collector in HotSpot that supports this
options, but work to also support it in G1 is ongoing. Since this option
is relatively new, and perhaps not yet widely known, I thought I’d write a few words about when and how to use it.
When is SoftMaxHeapSize useful?
As the name implies, this new option sets a soft limit on how large the Java heap can grow. When set, the GC will strive
to not grow the heap beyond the soft max heap size. But, the GC is still allowed to grow the heap beyond the specified
size if it really needs to, like when the only other alternatives left is to stall an allocation or throw an OutOfMemoryError
.
There are different use cases where setting a soft max heap size can be useful. For example:
- When you want to keep the heap footprint down, while maintaining the capability to handle a temporary increase in heap space requirement.
- Or when you want to play it safe, to increase confidence that you will not run into an allocation stall or have
an
OutOfMemoryError
because of an unforeseen increase in allocation rate or live-set size.
Let’s make up an example, to illustrate the first use case listed above. Pretend that your workload under normal conditions needs 2G of heap to run well. But once
in a while you see workload spikes (maybe you’re providing a service that attracts a lot more users a certain
day of the week/month, or something similar). With this increase in workload your application now needs, say, 5G to
run well. To deal with this situation you would normally set the max heap size (-Xmx
) to 5G to cover for the
occasional workload spikes. However, that also means you will be wasting 3G of memory 98% (or something) of the time when
it’s not needed, since those unused 3G will still be tied up in the Java heap. This is where a soft max heap size can come
in handy, which together with ZGC’s ability to uncommit unused memory allows you to
have your cake and eat it too. Set the max heap size to the max amount of heap your application will ever need (-Xmx5G
in this case), and set the soft max heap size to what your application needs under normal conditions (-XX:SoftMaxHeapSize=2G
in this case). You’re now covered to handle those workload spikes nicely, without always wasting 3G. Once the workload
spike has passed and the need for memory drops down to normal again, ZGC will shrink the heap and continue to do it’s best
to honor the -XX:SoftMaxHeapSize
setting. When those extra 3G of heap have been sitting unused for a while, ZGC will
uncommit that memory, returning it to the operating system for other processes (or the disk cache, or something else) to use.
Changing SoftMaxHeapSize at runtime
The SoftMaxHeapSize
option is also manageable, meaning it can be changed at runtime without having to restart
the JVM. You can change a manageable JVM option at runtime using the HotSpotDiagnosticMXBean or jcmd, like this.
jcmd <pid> VM.set_flag SoftMaxHeapSize <size>
The soft max heap size can not be set to a value greater than the max heap size. When not set on the command-line, the soft max heap size will default to the same value as the max heap size.
Uncommit aggressiveness
How aggressively ZGC uncommits unused memory can be controlled with -XX:ZUncommitDelay=<seconds>
, which defaults to
300 seconds (5 minutes). In other words, by default, memory must have been unused for 5 minutes before it’s eligible for
uncommit. Note that committing and uncommitting memory are relatively expensive operations. A too aggressive (short)
uncommit delay will just cause uncommitted memory to very soon be committed again, which can be a waste of CPU cycles
and might in the end also impact the overall performance of your application.
TL;DR
Using -XX:SoftMaxHeapSize=2G
-Xmx5G
will tell ZGC to keep the max heap usage at 2G, but it’s allowed to grow to 5G if it
otherwise would have resulted in an allocation stall or an OutOfMemoryError
. This is useful when you want to keep the memory
footprint down, while maintaining the capability to handle a temporary increase in heap space requirement.
For more information on ZGC, please see the OpenJDK Wiki, the GC section on Inside Java, or this blog.