Compare ZGC and G1 by workload and JDK version. Separate collector design goals from measured latency, throughput, and resource costs.
Compare ZGC and G1 by workload and JDK version. Separate collector design goals from measured latency, throughput, and resource costs.
ZGC vs G1 is a trade-off between pause-time goals, throughput, CPU, and memory headroom. The right choice depends on the JDK version and the workload. This guide explains the mechanisms and a measurement process, without treating illustrative workloads as benchmark results.
Start with the behavior you need to improve: application tail latency, GC pauses, allocation stalls, or total resource cost. Then compare collectors under the same load. Task scheduling and cancellation are separate concerns, covered in Java structured concurrency.
Start with the collectors’ mechanisms, then use measurements to check how those mechanisms affect the application.
G1 is the default collector on typical server-class HotSpot configurations. It uses regions, generations, concurrent marking, and stop-the-world evacuation. Its region size depends on heap sizing and JDK ergonomics.
G1 uses a configurable pause-time goal. A goal is not a maximum: the collector may exceed it under allocation pressure or other workload conditions. See the G1 tuning reference for the distinction.
ZGC became production-ready in JDK 15 and was designed with a single goal: keep pause times consistently tiny, independent of heap size. Its key innovations are:
ZGC is designed for low pause times, but a short GC pause is not an application latency guarantee. Allocation stalls, CPU contention, I/O, and safepoints can still affect requests. See the JDK 25 ZGC guide for its design and tuning boundaries.
G1’s core cycle includes:
G1 behavior depends on allocation, live data, available CPU, and evacuation work. Heap size alone does not determine whether the collector meets a service objective.
ZGC’s architecture minimizes pause time by performing almost everything concurrently:
ZGC is a useful candidate when GC pauses contribute to a latency problem. Confirm the benefit with application-level measurements rather than choosing a collector from heap size alone.
Measure application P95/P99 latency, achieved throughput, GC pause distribution, allocation stalls, process RSS, and CPU at the same offered load. A reduction in pause time can be offset by CPU contention or insufficient allocation headroom.
Collector design goals are useful for choosing a candidate. They do not predict a numerical improvement for a particular service. A useful comparison needs a reproducible harness and the underlying results.
Use the same JDK build, application, dataset, container limits, warm-up, and load profile. Change the collector first. Record steady load, bursts, recovery, and sustained overload separately. Publish the setup and raw results before drawing numerical conclusions.
For an HTTP service, correlate GC events with request latency. For a batch job, compare total runtime and cost. For a cache-heavy process, measure the live set and allocation rate. These are candidate workloads, not benchmark results.
G1 is a reasonable starting point for many server workloads. Test ZGC when pause sensitivity justifies the comparison, and retain the option to use G1 if its measured behavior better fits the service.
-XX:+UseG1GC
-Xms16g -Xmx16g
-XX:MaxGCPauseMillis=200Start with the defaults and change one setting at a time after measuring a specific problem.
-XX:+UseZGC
-Xms16g -Xmx16gStart with the collector defaults and a heap size that leaves allocation headroom. JDK 25 ZGC is generational without a ZGenerational flag. Treat ConcGCThreads as an advanced override and avoid copying a fixed value without measuring it.
Replay a representative workload or canary a small amount of traffic. Keep a rollback flag and compare both request latency and resource use. Adopt a collector only when it improves the measured service objective within the available CPU and memory budget.
Record the JDK, configuration, traffic, and capacity budget alongside the results so a later comparison can distinguish a collector effect from a workload or infrastructure change.
There’s no single “best” garbage collector. The right choice depends entirely on your workload.

Senior Technical Architect at HCLTech · working with Leonteq Security AG
I have 10+ years of experience building distributed systems and fintech platforms. I write about practical, non-obvious engineering details that official documentation often skips.
Scala, JVM, AI, and backend systems. I send practical articles when there is something worth reading.
Join the newsletter