It depends on the GC, with ZGC no. Particularly if you enable generational mode.
For other GCs like G1 and the parallel collector, when new gen is filled up the GC pauses the application in order to run a minor collection. For G1, major collections are ran in the background until the heap fully fills up. When that happens, the GC triggers stop the world GC.
A smaller heap size would cause those pauses to be more frequent but because the heap is smaller it means that ultimately the pauses will be limited in length.
ZGC is different. Without generational mode, ZGC is collecting the entire heap every time with it, ZGC will do the young old collections.
When a collection is triggered, ZGC flips a field to indicate a collection in progress, that flip is the only pause for the application under zgc (except the case that the heap fully fills) it typically finishes in microseconds. Once collection starts, the ZGC collector threads and the in progress application are running collections. The size of the heap really doesn't change much other than the background collection could last longer (slowing down the server, but not totally stopping it from being responsive).
The payment you make with ZGC is that you do burn more CPU cycles doing collections especially while the app is running. But for a game server, that hardly matters. What matters is that the server remains responsive in a timely fashion, which ZGC enables.
I don’t believe this is exactly how g1 works.
- It is divided into by default 2048 regions so it will be setting region size to 4mb means with an 8gb heap, and that you’ll get an inefficient collection once you have a 2mb+ object to deal with. So there is a value to setting a bigger heap size to get a bigger region size. The max is 32mb region size then after that iirc the region count bumps. https://docs.oracle.com/en/java/javase/17/gctuning/garbage-f...
- The young gen size also something that resizes dynamically and so having a bigger max heap will let that get larger and avoid pressure and promotion of objects that would otherwise just never get promoted in the first place (stop the world to move from new to old gen). I’ve never seen this stated anywhere I can think of but believe that I’ve observed it many thousands times.
- The reason that a Full GC occurs is because the application allocates too many objects that can't be reclaimed quickly enough, this isn’t just something that is always happening in the background , I would call full gcs a tuning problem, not everyone agrees in a given org fwiw, but I’ve been able to tune them out for nearly all workloads. https://docs.oracle.com/en/java/javase/17/gctuning/garbage-f...
TLDR , as long as I have enough ram for the working set (page cache etc) I’ve had good luck cranking g1gc very high in prod and avoiding long collection times all together. You see other large deployments do similar (was big in the Cassandra space back in the day, Instagram off the top of my head was running very large heaps with g1gc before anyone else I knew of).
> I don’t believe this is exactly how g1 works.
Everything you've posted is accurate but I also don't believe it contradicts what I said. I certainly simplified and I'm not suggesting G1 is a bad GC, it's one that we often use. I just think ZGC is better for the job of a game server.
G1 is an excellent GC if your application can tolerate periodic 50ms latency spikes (most applications can). My argument is that specifically for a game server, ZGC is better. That's because game servers typically have more than enough CPU horse power and added latency is detrimental to the experience. So trading off more CPU usage due to GC is a worthy tradeoff vs the added latency spikes.