What is ZGC?
4. Monitor Allocation Stall in logs 5. CPU overhead 5-15% — plan for it
Junior Level
ZGC (Z Garbage Collector) — collector with minimal pauses (< 1 ms), independent of Heap size. Throughput is 5-15% lower than G1.
Main advantage: Pauses are practically independent of Heap size and usually < 1 ms. Under extreme load, deviations are possible.
When to use:
- Real-time systems
- High-frequency trading
- When SLA < 10 ms
Middle Level
Key Technologies
1. Colored Pointers:
64-bit pointer:
Bits 0-41: object address
Bits 42-45: metadata (GC state)
→ GC understands object status just by reading the pointer
→ Without accessing object memory!
Colored Pointers — in 64-bit pointers, ZGC uses upper bits
to store metadata (generation, finalizable, weak, etc.).
JVM "colors" pointers, saving a separate data structure.
2. Load Barriers:
On every reference read:
→ Check pointer color
→ If object moved → fix address (Self-healing)
→ overhead ~5-15% CPU
Load Barriers — checks on EVERY reference read. If pointer
is "wrong" (object moved), Load Barrier automatically
fixes the pointer (Self-Healing).
3. Concurrent Evacuation:
Objects moved WITHOUT stopping the application!
→ Unlike G1 (Evacuation = STW)
→ Pause only for scanning GC Roots
ZGC vs G1
| Criterion | G1 | ZGC |
|---|---|---|
| Pause | 20-200 ms | < 1 ms |
| Throughput | High | -5-10% |
| Max Heap | 64 GB | 16 TB |
| Barriers | Write | Load |
Generational ZGC (Java 21+)
Before Java 21: single generation
→ Scanned entire Heap on every collection
Before Java 21, ZGC was non-generational — this caused Allocation Stalls
at high allocation rates. Generational ZGC (Java 21+) solves
this problem.
Java 21+: Young and Old generations
→ -50% CPU overhead
→ Allocation Stalls almost disappeared
When NOT to use
❌ CPU bound (90%+) → Load Barriers will make it worse
❌ Heap < 4 GB → G1 is more efficient
❌ 32-bit systems → ZGC requires 64-bit
Tuning
-XX:+UseZGC -XX:+ZGenerational # Java 21+
-XX:SoftMaxHeapSize=24g # Aggressive memory return
-XX:ConcGCThreads=4 # GC threads
Senior Level
Multi-mapping
One physical memory area mapped to 3 virtual addresses
→ Different metadata bit combinations
→ OS doesn't see pointer conflict
→ Enables "colored" pointers to work
Multi-mapping — technique of mapping one Heap area to several
virtual addresses, to encode metadata in pointer addresses.
Self-Healing Pointers
Load Barrier on read:
1. Read pointer
2. Check Remapped bit
3. If not Remapped → object moved
4. Compute new address
5. Update pointer in Heap (CAS)
6. Return new address
→ Pointer "heals" itself on every read
Allocation Stall Deep Dive
Cause: GC cannot mark garbage fast enough
→ Application threads wait for memory
Solutions:
1. Increase Heap
2. Increase ConcGCThreads
`ConcGCThreads` defaults to number of cores / 4.
Increase if you see Allocation Stall; decrease if GC takes too much CPU.
3. Generational ZGC (Java 21+)
4. Decrease Allocation Rate
Best Practices
- Java 21+ — use Generational ZGC
- ConcGCThreads = number of cores / 4
- SoftMaxHeapSize for containers
- Monitor Allocation Stall in logs
- CPU overhead 5-15% — plan for it
Senior Summary
- ZGC = Colored Pointers + Load Barriers + Conc Evacuation
- Pauses < 1 ms are constant, independent of Heap
- Generational (Java 21+) = -50% overhead
- Self-healing pointers via Load Barriers
- Allocation Stall = main risk
- CPU overhead 5-15% — price for low latency
Interview Cheat Sheet
Must know:
- ZGC: pauses < 1 ms, independent of Heap size (up to 16 TB); throughput 5-15% lower than G1
- Colored Pointers: upper bits of 64-bit pointer store metadata (generation, GC state)
- Load Barriers: on every reference read, check pointer color + Self-healing (if object moved)
- Concurrent Evacuation: objects moved WITHOUT STW (unlike G1, where Evacuation = STW)
- Multi-mapping: one physical Heap area mapped to 3 virtual addresses for metadata encoding
- Generational ZGC (Java 21+): split into Young/Old → -50% CPU overhead, Allocation Stalls almost disappeared
- When NOT to use: CPU bound (90%+), Heap < 4 GB, 32-bit systems
Common follow-up questions:
- Why is ZGC slower than G1 in throughput? — Load Barriers on every reference read add 5-15% CPU overhead
- What is Allocation Stall in ZGC? — GC cannot mark garbage fast enough → application threads wait; solutions: increase Heap, ConcGCThreads, or Generational ZGC
- What are Self-Healing pointers? — Load Barrier reads pointer → checks Remapped bit → if object moved, computes new address and updates pointer (CAS)
- Why Multi-mapping? — One Heap area to 3 virtual addresses → metadata encoding in addresses without pointer conflict
Red flags (DO NOT say):
- “ZGC uses Write Barriers” — ZGC uses Load Barriers (on read); G1 uses Write Barriers (on write)
- “ZGC works on 32-bit systems” — ZGC requires 64-bit system (Colored Pointers use upper bits)
- “ZGC is always better than G1” — for CPU-bound or batch processing, G1 gives better throughput
Related topics:
- [[12. What GC algorithms exist]]
- [[13. What is G1 GC]]
- [[15. What is Shenandoah GC]]
- [[16. What is stop-the-world]]
- [[17. Which GCs minimize stop-the-world pauses]]