I am testing the differences between G1GC and the CMS Garbage collectors. Running the same program yields different heap size usages (maybe as expected).
The below image shows the G1GC (left) compared to the CMS GC (right). G1GC manages to run the whole program whereas the when using the CMS, an outOfMemoryException
is raised.
Hence, my question: Why doesn't the CMS allow the used heap size to reach the available heap size? The heap size stops growing at 8.00GB with an out of memory exception when 10GB is available.
The short answer is that CMS is not as good as managing memory when the heap fills up as G1GC is. This is one of the reasons that CMS is being phased out.
A slightly longer answer is that the 2GB of unused space in CMS is reserved for evacuating objects in minor (copying) GCs of the Eden space. By contrast, G1GC seems to be able to adjust (shrink) the Eden space as the Tenured space fills up.
Note that this could actually be an artifact of an unrealistic benchmark. In a typical application, the minor collections will succeed in deleting most of the new objects. In your benchmark, it looks like nearly everything is remaining reachable, so most of the objects allocated end up in the Tenured space.
What can you do about it?
Switch to G1GC. In most cases it is better that CMS. (Eventually you won't have a choice. CMS was deprecated in Java 9, and has been removed in Java 14.)
You can change reduce the size of the Eden space: specifically adjust the NewSize and MaxNewSize. However, this has disadvantages for a normal workload. It is liable to lead to young objects being tenured too soon which will increase the load on the CMS collector.
There are newer collectors that are designed to work better with "full" heaps.