ZGC vs Shenandoah: Ultra-Low Latency GC for Java
In the world of high-performance computing—where microseconds matter—Java has often been scrutinized for its garbage collection (GC) pauses. Traditional GCs like G1 and Parallel GC introduce unpredictable stop-the-world (STW) pauses, making them unsuitable for high-frequency trading (HFT), real-time analytics, and low-latency microservices.
However, with the introduction of Z Garbage Collector (ZGC) and Shenandoah GC, Java now competes with low-latency languages like C++ and Rust. These collectors offer sub-millisecond pause times, even with multi-terabyte heaps, making them ideal for latency-sensitive applications.
This article explores:
- How ZGC and Shenandoah minimize pauses
- Key differences between the two collectors
- Real-world use cases and benchmarks
- Configuration best practices
1. The Need for Low-Pause Garbage Collectors
In financial trading, gaming, or telecom systems, response times must be consistent and predictable. Traditional GCs struggle with this because they:
- Stop application threads during major collections (STW pauses).
- Scale poorly with large heaps, leading to longer pauses.
- Introduce latency spikes, making SLAs hard to meet.
ZGC and Shenandoah solve these problems by performing almost all GC work concurrently, drastically reducing pause times.
2. ZGC: The Ultra-Low-Latency Collector
ZGC (Z Garbage Collector), introduced in JDK 11 and made production-ready in JDK 15, is designed for predictable, ultra-low pause times—often under 1 millisecond, regardless of heap size.
How ZGC Works
- Concurrent Phases: Marking, relocation, and reference processing happen without stopping application threads.
- Colored Pointers: Uses metadata bits in object references to track object states efficiently.
- Load Barriers: Ensures application threads see consistent memory views without long pauses.
When to Use ZGC
- High-frequency trading (HFT) – Where even a 10ms pause can lose trades.
- Real-time analytics – For consistent query response times.
- Large heaps (TB+) – Scales efficiently without increasing pauses.
Example Configuration
1 | java -XX:+UseZGC -Xmx32g -Xms32g -XX:+AlwaysPreTouch -jar app.jar |
(-XX:+AlwaysPreTouch
reduces runtime memory allocation delays.)
3. Shenandoah GC: Balanced Latency and Throughput
Shenandoah, developed by Red Hat and integrated into OpenJDK, offers sub-10ms pauses while maintaining good throughput. Unlike ZGC, it performs even root scanning concurrently, further reducing pauses.
How Shenandoah Works
- Brooks Pointers: Each object has an additional forwarding pointer, enabling concurrent compaction.
- Concurrent Evacuation: Moves objects without stopping application threads.
- Better for Mixed Workloads: Balances latency and throughput better than ZGC in some cases.
When to Use Shenandoah
- Real-time data processing – Where both speed and consistency matter.
- Cloud-native microservices – For smoother scaling under load.
- Applications with moderate heap sizes (up to hundreds of GB).
Example Configuration
1 | java -XX:+UseShenandoahGC -Xmx16g -Xms16g -XX:ShenandoahGCHeuristics=adaptive -jar app.jar |
(-XX:ShenandoahGCHeuristics=adaptive
optimizes for varying workloads.)
4. Benchmarks and Real-World Performance
Latency Comparison
GC | Avg Pause Time | Max Pause Time | Heap Scalability |
---|---|---|---|
ZGC | <1ms | ~2ms | TB+ |
Shenandoah | 1-10ms | ~20ms | Up to ~200GB |
G1 GC | 50-200ms | 500ms+ | Up to ~100GB |
(Sources: Oracle ZGC Docs, Red Hat Shenandoah Blog)
Throughput Impact
- ZGC sacrifices some throughput for lower latency.
- Shenandoah offers better throughput in mixed workloads.
- G1 is still better for pure throughput if pauses are acceptable.
5. Choosing the Right GC for Your Application
Use Case | Recommended GC |
---|---|
Ultra-low-latency (HFT, real-time) | ZGC |
Balanced (microservices, cloud apps) | Shenandoah |
High-throughput batch processing | G1 or Parallel GC |
Final Recommendations
- For strict sub-millisecond pauses: Use ZGC.
- For a balance of latency and throughput: Use Shenandoah.
- For legacy applications: G1 GC is still a safe default.
6. Further Reading
7. Conclusion
With ZGC and Shenandoah, Java is now a strong contender for low-latency, high-performance applications. By choosing the right garbage collector and tuning it properly, developers can achieve near-real-time performance without switching to C++ or Rust.