We recently modified what is the ideal JVM heap size for production on our core microservices, scaling it up to 32GB. However, we are now experiencing massive stop-the-world pauses with G1GC. Does a larger heap inherently degrade garbage collection efficiency, or do we just need to tune our max pause time targets to match?
3 answers
When you scale your heap up to 32GB, G1GC can struggle if it is left entirely on default parameters. While G1GC is designed to handle larger heaps by dividing the memory into smaller, manageable regions, a massive heap means it has significantly more regions to scan and manage. If your application creates objects at a very high rate, the garbage collector might fail to keep up, leading to full concurrent mark cycles or devastating stop-the-world pauses. You should explicitly tune your initiation flags alongside heap adjustments.
Are you currently setting the MaxGCPauseMillis flag alongside your large heap configuration, or are you letting the JVM use its default pause time targets?
With a 32GB heap, you might want to look into switching to the ZGC or Shenandoah collectors if low-latency pause times are your team's primary production goal.
Excellent point about ZGC. It handles large heaps effortlessly, keeping pause times under milliseconds, which completely redefines what is the ideal JVM heap size for production.
We actually set MaxGCPauseMillis to 200ms, Douglas. However, we realized that if the heap is too packed with long-lived objects, the JVM will repeatedly miss this target, causing longer sequential pauses as it desperately tries to clear out space to prevent an impending allocation failure.