SoftMaxHeapSize is ignored in ZGC

62 views Asked by At

I have below settings for ZGC, when using extended memory, memory is not given back, it looks like SoftMaxHeapSize is ignored totally, only when I do a forced GC cycle memory is given back. What might be the reason and is it worth a bug report?

JDK: graalvm-jdk-21.0.1

-Xmx24G
-XX:+UnlockExperimentalVMOptions
-XX:+UseZGC
-XX:+ZGenerational
-XX:+UseNUMA
-XX:SoftMaxHeapSize=4G
-XX:ZUncommitDelay=16

I created a gist for the GC log, at [191.338s] there is a full GC forced: https://gist.github.com/thhart/d4acb994de1866eeedcce428e583b89a

1

There are 1 answers

1
aled On

SoftMaxHeapSize is a 'soft' limit to the heap size. It doesn't prevents the heap to grow beyond that limit when needed. It is a best effort limit. It should be expected that the heap may grow over it. Then it is up to the GC on when to reclaim memory over that limit.

According to Oracle garbage collection documentation:

ZGC has another command-line option related to the heap size named -XX:SoftMaxHeapSize. It can be used to set a soft limit on how large the Java heap can grow. ZGC will strive to not grow beyond this limit, but is still allowed to grow beyond this limit up to the maximum heap size. ZGC will only use more than the soft limit if that is needed to prevent the Java application from stalling and waiting for the GC to reclaim memory. For example, with the command-line options -Xmx5g -XX:SoftMaxHeapSize=4g ZGC will use 4GB as the limit for its heuristics, but if it can't keep the heap size below 4GB it is still allowed to temporarily use up to 5GB.

This blog post provides more details and examples of how it behaves and suggestions on how to reclaim memory. Note that playing with these configurations can cause performance issues. Thorough performance testing is always recommended when changing GC configurations.

Uncommit aggressiveness

How aggressively ZGC uncommits unused memory can be controlled with -XX:ZUncommitDelay=, 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.