What GC algorithms exist?
4. Don't use G1 if: 5. Don't start with tuning — first check for leaks 6. Monitor GC logs 7. Allocation Stall = increase Heap or ConcGCThreads
Junior Level
GC Algorithms — different ways of “garbage cleanup” in memory.
Three main approaches:
| Algorithm | How it works | Analogy |
|---|---|---|
| Copying | Copies live objects to new area | Moving to a new house |
| Mark-Sweep | Marks live, removes dead | Throwing trash from a room |
| Mark-Compact | Marks + shifts live objects | Cleanup + organizing |
Why different algorithms:
- Copying is efficient when there’s lots of garbage (copy only 2% live).
- Mark-Sweep is efficient when there’s little garbage (no need to copy).
- Mark-Compact is needed to fight fragmentation.
Main GCs in Java:
- G1 GC — default (Java 9+)
- ZGC (Java 15+) — pauses < 1 ms, independent of Heap size. Throughput 5-10% lower than G1.
- Parallel GC — for maximum processing speed
Middle Level
GC Triangle
Latency
/ \
/ \
Throughput ── Footprint
Cannot optimize all three!
Latency — how long the application "freezes" during GC (pauses).
Throughput — what percentage of time the application runs vs collecting garbage.
Footprint — how much memory the JVM consumes.
Modern GCs
| GC | Pause | Throughput | For what |
|---|---|---|---|
| Serial | 100-500 ms | Low | Small applications |
| Parallel | 100-1000 ms | Maximum | Big Data, batch |
| G1 | 20-200 ms | Good | Web, Spring Boot |
| ZGC | < 1 ms | -5-10% | Real-time, HFT |
| Shenandoah | < 1 ms | -5-10% | Alternative to ZGC |
Allocation Stall
Application creates garbage faster than GC collects
→ Thread stops and waits for GC
→ Pause: hundreds of milliseconds
Solution: more Heap or fewer allocations
Full GC
All GCs have a "Plan B" — Full GC
→ If concurrent collection can't keep up
→ Full STW of all generations
→ Sign of a leak or misconfiguration
Senior Level
Write vs Load Barriers
G1: Write Barriers
→ On reference write: mark Card Table
→ overhead on write
ZGC: Load Barriers
→ On reference read: check pointer color
→ Self-healing: fix address on the fly
→ overhead on read
SATB vs Incremental Update
SATB (Snapshot-At-The-Beginning):
→ Marks everything that was alive at marking start
→ Floating Garbage (objects that became unreachable after snapshot,
will be collected in the next cycle)
→ Used in G1
Incremental Update:
→ Tracks new references
→ Less Floating Garbage
→ More overhead
Generational ZGC (Java 21+)
Split into Young/Old generations
→ -50% CPU overhead
→ Young GC more often and faster
→ Practically no Allocation Stalls
Epsilon GC
"No-op GC" — allocation only
→ Doesn't collect garbage at all
→ On OOM → JVM crashes
Epsilon GC — "empty" collector: doesn't collect garbage at all.
Throws OOM as soon as Heap is full.
Useful for benchmarks and tests with guaranteed lifetime.
Why:
- Benchmarks (exclude GC influence)
- Short-lived functions
- Off-heap work
Best Practices
- G1 GC — default for most cases
- ZGC (Java 21+) — for SLA < 10 ms
- Parallel — for Big Data
- Don’t use G1 if:
- SLA < 10 ms — use ZGC
- Batch processing without latency requirements — use Parallel GC
- Don’t start with tuning — first check for leaks
- Monitor GC logs
- Allocation Stall = increase Heap or ConcGCThreads
Senior Summary
- GC Triangle: Latency ↔ Throughput ↔ Footprint
- Barriers: Write (G1) vs Load (ZGC)
- SATB = Floating Garbage trade-off
- Generational ZGC — best low-latency GC
- Allocation Stall = catastrophe for latency
- Epsilon — for tests, not production
- Best garbage = not created
Interview Cheat Sheet
Must know:
- GC Triangle: cannot optimize Latency, Throughput and Footprint simultaneously
- Copying — copies live (Young Gen, efficient at 98% garbage); Mark-Sweep — marks + removes (Old Gen); Mark-Compact — marks + shifts (no fragmentation)
- Serial GC: 1 thread, long pauses — NOT for servers; Parallel GC: max throughput, long pauses — for Big Data
- G1 GC: regions 1-32 MB, Mixed GC, pauses 20-200 ms — balance; ZGC: Colored Pointers + Load Barriers, < 1 ms, overhead 5-15%
- Allocation Stall: application creates garbage faster than concurrent GC → thread freezes
- SATB (G1): Floating Garbage (objects that became unreachable after snapshot, collected in next cycle)
- Epsilon GC: “no-op”, doesn’t collect garbage — only for benchmarks
Common follow-up questions:
- Why does ZGC use Load Barriers, while G1 uses Write Barriers? — ZGC checks pointer on read (self-healing); G1 marks Card Table on write. Load Barriers are more expensive (~5-15 ns vs ~1-2 ns)
- What is Floating Garbage? — Objects that died AFTER marking started; won’t be collected in this cycle (SATB trade-off)
- When is Full GC a sign of a problem? — When it happens regularly (every few minutes); sign of a leak or misconfiguration
- Why is Generational ZGC (Java 21+) better than single-generational? — Split into Young/Old → -50% CPU overhead, Young GC more often and faster
Red flags (DO NOT say):
- “ZGC is always better than G1” — ZGC sacrifices 5-15% throughput; for batch processing G1/Parallel is better
- “I’ll start with tuning GC parameters” — first check for leaks and code; GC tuning won’t fix bad code
- “Serial GC is suitable for production server” — 1 thread, long pauses; only for small CLI utilities
Related topics:
- [[4. What is Garbage Collection]]
- [[13. What is G1 GC]]
- [[14. What is ZGC]]
- [[15. What is Shenandoah GC]]
- [[17. Which GCs minimize stop-the-world pauses]]