JVM Garbage Collectors: From Serial to ZGC – A Complete Overview
This article walks through the evolution of Java garbage collectors—from the early Serial collector to modern low‑latency ZGC and Shenandoah—explaining how throughput, pause time, and safepoints shape each collector’s design and what changes matter when upgrading from JDK 8 to JDK 17.
1. Evaluating a GC: Throughput vs Pause
Before comparing collectors you need two conflicting metrics: Throughput (user code time / (user code time + GC time)) favors batch‑style workloads, while Pause Time (duration of a single GC‑induced stop‑the‑world) is critical for interactive services. Improving one usually harms the other, so selection depends on the target scenario.
GC pause originates from Stop‑The‑World (STW) pauses required to obtain a stable snapshot of object references. Threads can only stop at Safepoints , specific locations where the JVM can safely pause them. Too many safepoints increase overhead; too few delay pauses.
2. Classic Generational Trio: Serial, ParNew, Parallel
Serialis a single‑threaded collector that pauses all user threads for the entire collection. It works well on single‑core or small‑heap client apps and serves as a fallback for other collectors. ParNew is the multithreaded version of Serial, using several GC threads to shorten STW. It is the only young‑generation collector that can be paired with CMS (the classic “ParNew + CMS” server combo). Parallel Scavenge (often called Parallel) also uses multiple threads but targets high throughput; it is the default collector in JDK 8, combined with Parallel Old for the old generation. Its main drawback is long STW pauses during full GC.
Note the difference: parallel means multiple GC threads while the application is paused; concurrent means GC threads run alongside user threads.
3. CMS: The First Real Concurrent Collector
CMS (Concurrent Mark‑Sweep) aims to minimize pause time by performing most work concurrently. It follows four phases:
Initial Mark (brief STW, marks GC roots only).
Concurrent Mark (no STW, GC threads traverse the object graph).
Remark (STW, fixes marks changed during concurrent phase).
Concurrent Sweep (no STW, reclaims dead objects).
While CMS reduces pauses, it has serious drawbacks: high CPU usage, generation of “floating garbage”, possible Concurrent Mode Failure that falls back to a full Serial Old GC, and memory fragmentation.
4. Tri‑color Marking: The Core of Concurrent Marking
Concurrent marking can miss objects, leading to two problems:
Over‑mark (floating garbage) : dead objects are mistakenly kept alive.
Under‑mark (leak) : live objects are incorrectly reclaimed, causing crashes.
Leak occurs when a black object gains a reference to a white object while the white object loses all references from gray objects. The fix is a write barrier that records such changes, enabling a second “remark” phase. CMS uses the “incremental update” barrier; G1 and Shenandoah use the SATB (Snapshot‑At‑The‑Beginning) barrier.
5. G1: Region‑Based Design for Large Heaps
G1 became the default collector from JDK 9 onward. It divides the heap into equal‑sized Regions (1–32 MB each) that can dynamically act as Eden, Survivor, or Old. A special Humongous Region holds very large objects.
G1 tracks garbage amount and collection cost per Region, builds a “cost‑benefit” ranking, and during each pause (bounded by -XX:MaxGCPauseMillis, default 200 ms) it collects the most profitable Regions first. This yields predictable pauses and avoids the fragmentation seen in CMS.
However, G1 maintains per‑Region remembered sets, consuming 10–20 % of heap memory, making it less suitable for small heaps; it shines on large heaps (≥ 6 GB).
6. ZGC & Shenandoah: Millisecond‑Level Pauses
ZGC and Shenandoah push pause times into the low‑millisecond range regardless of heap size (ZGC targets <10 ms). They achieve this by making even object relocation concurrent.
Colored Pointers (ZGC) : store mark and relocation state in spare bits of object references.
Load Barriers : on each reference read, check the pointer’s color; if the object has moved, the reference is automatically “self‑healed” to the new address.
Both collectors sacrifice some throughput for ultra‑low latency and are intended for very large heaps with stringent latency requirements.
7. JDK 8 → 17 Collector Changes
Key differences between JDK 8 and JDK 17:
Default collector switched from Parallel to G1 .
CMS was deprecated in JDK 9 and removed in JDK 14; it is no longer available in JDK 17.
ZGC and Shenandoah became production‑ready in JDK 15 and are available by default in JDK 17.
When upgrading, you must adjust GC‑related flags (e.g., remove -XX:+UseConcMarkSweepGC) and consider the new default pause‑focused behavior of G1.
8. Summary
Two evaluation axes: throughput vs pause; pauses stem from STW and safepoints.
Generational trio: Serial (single‑thread, fallback), ParNew (multithreaded, CMS partner), Parallel (throughput‑oriented, JDK 8 default).
CMS: first concurrent collector, four‑phase cycle, suffers from CPU contention, floating garbage, fragmentation, and possible mode failure.
Tri‑color marking introduces leak risks; write barriers (incremental update or SATB) fix them.
G1: region‑based, predictable pauses, no fragmentation, best for large heaps.
ZGC/Shenandoah: colored pointers/load barriers enable concurrent relocation, delivering millisecond pauses at the cost of some throughput.
JDK 8 → 17 highlights: Parallel → G1 default, CMS removed, ZGC/Shenandoah now production‑ready.
Next article will cover GC tuning and online troubleshooting, including how to read GC logs ( -XX:+PrintGCDetails vs -Xlog:gc) and use tools like jstat, jmap, and Arthas.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
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.
