Understanding and Tuning Z Garbage Collector (ZGC) for Low‑Latency Java Applications
This article explains the principles, features, and workflow of Java's Z Garbage Collector, provides detailed configuration and logging guidance, and shares AutoMQ's practical tuning experiences that achieve sub‑millisecond pause times and improved performance for latency‑sensitive backend services.
In Java applications, garbage collection (GC) reclaims unused memory but can cause stop‑the‑world (STW) pauses that affect latency‑sensitive services.
ZGC, introduced in JDK 11, is a low‑latency concurrent collector that reduces STW pauses to sub‑millisecond levels by using concurrent marking, relocation, and colored pointers.
Key characteristics of ZGC include scalability from 8 MiB to 16 TiB, pause times typically below 1 ms, predictable performance independent of heap size, throughput comparable to G1GC, and automatic tuning of many parameters.
The collector relies on colored pointers, where the high bits of an object reference encode metadata such as Marked0/Marked1, Remapped, and Finalizable flags. Read barriers in the JIT‑compiled code check these colors and trigger fixes when a “bad” color is observed.
ZGC partitions the heap into regions (small, medium, large) that can be allocated, freed, or reclaimed independently, enabling efficient compaction and migration. Objects may be moved via non‑local or in‑place relocation, with a forwarding table stored off‑heap.
The GC workflow consists of alternating STW and concurrent phases: start‑mark, concurrent mark & remap, end‑mark, concurrent prepare relocation, start‑relocate (STW), concurrent relocate, and cleanup. Most work happens concurrently, keeping pause times minimal.
Configuration options allow fine‑grained control, e.g., -XX:+UseZGC , heap size -Xmx / -Xms , dynamic GC thread count -XX:+UseDynamicNumberOfGCThreads , -XX:ConcGCThreads , large pages -XX:+UseLargePages , and tuning parameters such as -XX:ZAllocationSpikeTolerance and -XX:ZCollectionInterval .
Logging can be enabled with -Xlog:gc*:gc.log , producing tags like gc,start , gc,phases , gc,load , gc,mmu , gc,ref , gc,reloc , and gc,heap that detail pause durations, marking times, memory usage, and reference processing.
Since its debut, ZGC has evolved: JDK 13 expanded heap limits, JDK 14 added macOS/Windows support, JDK 15 became production‑ready, JDK 16 introduced concurrent thread‑stack scanning and in‑place relocation, JDK 17 added macOS/AArch64, JDK 18 added PowerPC, and JDK 21 brought generational ZGC.
AutoMQ, a cloud‑native streaming system compatible with Apache Kafka, adopts ZGC to achieve sub‑50 µs STW pauses, delivering sub‑millisecond end‑to‑end latency. Tuning includes fixing heap size (e.g., -Xms6g -Xmx6g -XX:MaxDirectMemorySize=6g -XX:MetaspaceSize=96m ), adjusting -XX:ZCollectionInterval=5s , and increasing -XX:ZAllocationSpikeTolerance for traffic spikes.
Case studies show how proper heap sizing prevents allocation stalls, how periodic GC mitigates sudden load spikes, and how addressing memory leaks and off‑loading metadata reduces GC pressure in large clusters. Generational ZGC in JDK 21 further alleviates high‑survivor‑object workloads.
Benchmarks comparing ZGC with G1GC on a 2 vCPU, 16 GiB instance demonstrate dramatically lower latency and comparable CPU usage when ZGC is used.
The article concludes that understanding ZGC’s mechanisms and applying targeted configuration can substantially improve performance and stability of Java backend services.
High Availability Architecture
Official account for High Availability Architecture.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.