Question 12 · Section 3

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

Language versions: English Russian Ukrainian

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

  1. G1 GC — default for most cases
  2. ZGC (Java 21+) — for SLA < 10 ms
  3. Parallel — for Big Data
  4. Don’t use G1 if:
    • SLA < 10 ms — use ZGC
    • Batch processing without latency requirements — use Parallel GC
  5. Don’t start with tuning — first check for leaks
  6. Monitor GC logs
  7. 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]]