MiddlePerformanceRareNot answered yet
How does the low-pause collector ZGC keep stop-the-world (STW) pauses sub-millisecond?
ZGC does marking, relocation, and reference remapping concurrently with the running application. Coloured pointers keep GC state in unused address bits, and a load barrier on every reference read lazily remaps a stale pointer. Only brief root scans are stop-the-world, so pause time tracks the root-set size, not the heap size.
- ✗Thinking
ZGCis justG1with more GC threads rather than a concurrent collector - ✗Assuming
ZGCpause time grows with heap size like the older collectors - ✗Confusing the load barrier on reads with a write barrier, or assuming no barrier at all
- →What work does
ZGCstill have to do inside a stop-the-world pause? - →Why does
ZGCtrade away some throughput for its sub-millisecond pauses?
Why the pause does not grow with the heap
A classic collector stops the application for a time proportional to the work: the more live objects, the longer the pause. ZGC takes that work out of the pause entirely.
- Marking and relocation run concurrently. They proceed on background threads while the application keeps running.
- Coloured pointers. A 64-bit address does not use every bit;
ZGCstores object-state marks (marked, remapped) in the spare bits. GC metadata needs no extra header word. - Load barrier. Every reference read executes a short barrier: if the coloured bits show the object has moved, the reference is repaired at read time — lazily, one at a time. The application never observes a stale address.
- Only roots stay in the pause. Thread stacks and global roots must be scanned synchronously. Their count scales with the number of threads, not with heap size — hence a sub-millisecond pause even on a terabyte heap.
The price is throughput: a barrier on every reference read plus background GC threads take cycles away from the application.