← Recipes

Low-Latency API with ZGC

Choose ZGC when short GC pauses are more important than maximum throughput.

Flags

-XX:+UseZGC-Xmx-Xlog:gc*

-XX:+UseZGC selects the Z Garbage Collector. ZGC performs most GC work concurrently with application threads, making it attractive for services with strict tail latency goals and larger heaps.

Flag details

-XX:+UseZGC
Selects ZGC, a scalable low-latency collector. In Java 25, ZGC uses generational behavior by default, so young objects can be collected more efficiently than old long-lived objects.
-Xmx8g
Gives ZGC a maximum heap budget. ZGC needs enough free space to collect concurrently while the application keeps allocating.
-XX:+AlwaysPreTouch
Touches heap pages at startup so physical memory is committed early. This can make latency more predictable after startup, but increases startup time and commits memory immediately.
-Xlog:gc*
Shows ZGC cycles, allocation stalls, heap capacity changes, relocation activity, and whether concurrent collection is keeping up.

How ZGC works

ZGC is designed to keep GC pauses very short by doing marking, relocation, and reference processing work concurrently with application threads. It uses load barriers so application code can safely access objects while the collector is moving them.

Generational ZGC separates young and old objects. Since most objects die young, collecting the young generation more often reduces CPU and memory pressure compared with treating the whole heap uniformly. ZGC still needs CPU headroom; if allocation outruns concurrent collection, the application can see allocation stalls.

When to use it

Use this for latency-sensitive APIs, trading platforms, real-time-ish request processing, and services where occasional long G1 pauses are unacceptable. Give ZGC enough CPU and heap headroom so concurrent collection can keep up with allocation.

On modern JDKs, ZGC requires little manual tuning. Start with -XX:+UseZGC, heap limits, and logs.

Java version support

ZGC arrived as an experimental collector in Java 11 and became production-ready in Java 15. Generational ZGC arrived in Java 21, became the default ZGC mode in Java 23, and the old non-generational mode was removed in Java 24. On Java 25, -XX:+UseZGC means generational ZGC.

Related JEPs

Examples

java -XX:+UseZGC -Xmx8g \
  -Xlog:gc*:file=logs/zgc.log:time,uptime,level,tags \
  -jar latency-api.jar

Use this as the first ZGC production experiment: one collector flag, heap limit, and logs.

java -XX:+UseZGC -Xms4g -Xmx4g \
  -XX:+AlwaysPreTouch \
  -jar latency-api.jar

Use this when startup can be slower but you want heap pages committed before traffic arrives.

Verify

Look for allocation stalls, GC cycle frequency, CPU saturation, and request tail latency under realistic load.