Skip to main content

Garbage Collection: Lifecycle, Algorithms & STW

HotSpot reclaims unreachable heap objects automatically. This page is the interactive home for how an object ages (Eden β†’ Survivors β†’ Old β†’ reclaimed), which algorithms young/old use, and how collectors evolved to shrink Stop-The-World (STW) pauses.

For JVM architecture (Heap, Stack, PC, Metaspace) see JVM Internals.


1. Why Generational GC?

Weak generational hypothesis:

  1. Most objects die young (request DTOs, short-lived builders, temporaries).
  2. Objects that survive early collections tend to live a long time (singletons, caches, pools).

HotSpot splits the Java Heap into a Young generation (cheap, frequent Mark-Copy) and an Old generation (rarer, more expensive cycles). That split is why S0/S1 exist and why Minor GC is usually cheap compared to Full GC.


2. Heap Layout: Eden, S0, S1, Old

Click regions for ratios, GC role, and flags.

Heap MemoryGC ManagedYoung GenerationEden~80% sizeS0 (From)~10% sizeS1 (To)~10% sizeOld Gen (Tenured)Major GC Mark-Compact

Heap Memory (GC-Managed Shared Area)

Capacity Ratio: 100% of Heap Allocation

Overview: The primary memory workspace of the JVM where all objects, class instances, and array payloads are allocated.

  • GC Role & Management: Scanned continuously by minor, major, and mixed GC threads to recover unreachable blocks.
  • JVM Sizing Flags:
    • -Xms (Initial Heap size)
    • -Xmx (Maximum Heap size)
    • -XX:MinHeapFreeRatio
    • -XX:MaxHeapFreeRatio

πŸ’‘ Click on any segment (Heap, Young Gen, Eden, S0, S1, or Old Gen) in the diagram above to inspect JVM memory sizing parameters.

SpaceRole
EdenBirthplace of almost all new allocations (TLAB)
S0 / S1Twin survivor spaces; one is empty (To) before each young GC; roles flip
Old (Tenured)Long-lived objects after age threshold or survivor overflow

Locals vs objects: method locals and parameters live on the stack and vanish when the frame returns. Only heap objects go through Eden β†’ Survivor β†’ Old.


3. Object Lifecycle (Animate)

Follow one object from allocation to reclamation. Press β–Ά Animate or click a stage.

Object Lifecycle: Eden β†’ S0/S1 β†’ Old β†’ Collected
YOUNG GENERATIONEdennew objectsTLAB bump-pointerS0 SurvivorS1 SurvivorOLD GENERATIONTenuredage β‰₯ threshold / overflowlong-lived reachable objectsUnreachable β†’ ReclaimedMajor / Mixed / Concurrent cycleMinor GC: Mark-Copy inside Young Β· roles of S0/S1 flip each cyclePromotion: age β‰₯ MaxTenuringThreshold (default 15) or Survivor pressureStack locals β‰  heap lifecycle β€” only objects on the Heap are tenured / GC’d
Press β–Ά Animate or select a stage to follow an object from Eden through S0/S1 into Old until reclamation.

S0 and S1 swap From/To each Minor GC. Age lives in the object header until promotion or death in Young.

Lifecycle in one breath

  1. Allocate in Eden.
  2. Minor GC copies live Eden objects into a Survivor (To); Eden is wiped.
  3. Next Minor GC: live objects in From + Eden copy into the other Survivor; age++; spaces swap.
  4. Age β‰₯ -XX:MaxTenuringThreshold (default 15) or Survivor pressure β†’ promote to Old.
  5. When unreachable from GC Roots, a later Old / mixed / concurrent cycle reclaims the memory.

4. How GC Decides β€œGarbage”

HotSpot does not use reference counting (circular refs would leak). It uses reachability analysis from GC Roots:

  • Locals / parameters on active thread stacks
  • Static fields
  • JNI references
  • Threads / some internal JVM handles

Anything not reachable from a root is garbage β€” even if objects still point at each other.

A Java memory leak is usually β€œstill reachable from a root but forgotten by the app” (static Map, ThreadLocal, listeners) β€” GC cannot help until the reference is cleared.


5. Algorithms & STW Evolution

Select a collector on the timeline, then an algorithm chip. Highlighted chips are the ones that collector relies on.

GC Algorithms & STW Evolution
Collectors (how STW shrank over time)
Serial
β†’
Parallel
β†’
CMS
β†’
G1
β†’
ZGC
STW ↓ latency-critical
Algorithm primitives
G1 (Garbage-First)
STW: Bounded STW evacuations; concurrent mark; mixed GC for Old

Default on modern HotSpot. Heap is split into equal regions (Eden/Survivor/Old/Humongous). G1 collects regions with the most garbage first under a pause-time goal, using concurrent marking and young/mixed evacuations.

Under the hood
  • Remembered sets track cross-region refs so a region can be collected without scanning the world.
  • SATB write barrier during concurrent mark.
  • Mixed GC: young + selected old regions in one pause window.
  • Still has STW β€” engineered to meet -XX:MaxGCPauseMillis, not zero.
Failure modes
  • to-space exhausted / evacuation failure β†’ Full GC (look for Pause Full in logs).
  • Humongous allocation storms fragment region map.
Notes
  • Tune pause goal + heap size together; tiny heap + tiny pause is impossible.
  • Default choice unless latency SLO demands ZGC.
-XX:+UseG1GC-XX:MaxGCPauseMillis=200-XX:InitiatingHeapOccupancyPercent
Select an algorithm chip (highlighted ones apply to G1 (Garbage-First)). Mark-Copy powers Young; concurrent mark is how modern collectors cut STW.

Simulate Mark-Copy (young Minor GC) or Mark-Compact (old slide) with moving arrows β€” one focused sim, not every collector.

Algorithm Simulation
EdenAΓ—BΓ—CΓ—From DΓ—ETo (emptyβ†’live)GC Rootsstacks / staticsGreen = live Β· Gray = dead (not copied) Β· Cost ∝ live set, not dead countYoung Minor GC = Mark-Copy into empty To, then flip S0/S1
1. Before Minor GC

Eden is full of live (green) and dead (gray) objects. From may hold survivors from the last cycle. To is empty β€” required spare space for Mark-Copy.

Under the hood
  • Young layout: Eden + From + To (S0/S1 with flipped roles).
  • Dead objects are never visited one-by-one later β€” only live ones are copied.
  • STW begins: mutator threads pause for the young collection.
Notes
  • Cost will scale with live bytes in Eden+From, not with how many dead objects exist.

Mark-Copy: evacuate live objects into empty To, abandon dead space, flip survivors.

Long STW freezes TCP handling β€” Kubernetes probes can kill a pod that is only β€œpaused,” not dead. That operational pain is why G1 pause goals and ZGC concurrent relocate exist.


6. G1 Regions

G1 divides the heap into equal-sized regions. Each region is Eden, Survivor, Old, or Humongous. Click for region semantics.

G1 Region-Based Heap Layout (Logical Divisions)EdenEden [E]OldOld [O]SurvivorSurv [S]EdenEden [E]OldOld [O]HumongousHum [H]OldOld [O]EdenEden [E]FreeFree [F]OldOld [O]OldOld [O]EdenEden [E]FreeFree [F]OldOld [O]OldOld [O]SurvivorSurv [S]FreeFree [F]OldOld [O]

Eden Region (Young Generation)

Overview: Logical young generation region. Sized dynamically based on allocation throughput.

  • Tuning flags: -XX:G1NewSizePercent (Initial size, default 5%) | -XX:G1MaxNewSizePercent (Max size, default 60%)
  • GC Collection Behavior: Minor GCs evacuate surviving objects to Survivor regions, emptying the Eden regions completely to become Free.
  • Under the Hood Mechanics:
    • Objects are allocated here via TLABs to avoid synchronization locks.
    • Sizing is adjusted dynamically by G1 between collections to meet user pause time targets (-XX:MaxGCPauseMillis).

πŸ’‘ Click on any region box (Eden, Survivor, Old, Humongous, Free) on the grid to inspect its logical partition rules.

  • Young GC: evacuate Eden + Survivors into survivor/old regions.
  • Concurrent mark: find reclaimable Old regions.
  • Mixed GC: young + high-garbage Old regions in one pause budget (MaxGCPauseMillis).
  • Full GC in logs (Pause Full) means evacuation/concurrent cycle failed to keep up β€” investigate promotion, humongous objects, or heap size.


7. Tri-Color Marking & Concurrent Collector Barriers

Modern low-latency collectors (G1, Shenandoah, ZGC) perform object marking concurrently while application worker threads (mutators) continue to run. They model object reachability using the Tri-Color Marking Abstraction:

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ TRI-COLOR MARKING ABSTRACTION β”‚
β”‚ β”‚
β”‚ β€’ WHITE: Unvisited objects. At the end of marking, white objects are dead. β”‚
β”‚ β€’ GREY: Visited by GC, but its outgoing field references are not yet scannedβ”‚
β”‚ β€’ BLACK: Visited AND all outgoing references scanned. Guaranteed live. β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

The Concurrent Invalidation Hazard

Because mutator threads run simultaneously with the GC marking threads, a mutator can break reachability assumptions if:

  1. Mutator clears a pointer from a Grey object to a White object.
  2. Mutator attaches that White object to an already-scanned Black object.
  • If unhandled, the GC never visits the white object (since black objects are never rescanned), resulting in catastrophic silent data corruption (premature reclamation of live objects!).

Barriers: SATB vs. Incremental Update vs. Load Barrier

  • Snapshot-At-The-Beginning (SATB - G1 GC): Uses a Pre-Write Barrier. Before overwriting an old field reference, it logs the old reference into a per-thread SATB buffer. Guarantees that any object that was live at the start of GC remains considered live.
  • Incremental Update (CMS / Shenandoah): Uses a Post-Write Barrier. When a black object receives a reference to a white object, it downgrades the black object back to grey.
  • Load Barrier (ZGC): Intercepts reference reads (getfield) rather than writes. If an object pointer has not been remapped, the load barrier intercepts the read in ~2 nanoseconds, updates the pointer to its new relocated address, and returns the valid object immediately ("Self-Healing").

8. ZGC Colored Pointers & Generational ZGC (Java 21)

ZGC achieves sub-millisecond pause times on heaps ranging from 8MB to 16TB by executing all mark, evacuate, and relocate phases concurrently.

Colored Pointers & Virtual Memory Multi-Mapping

On 64-bit platforms, ZGC stores metadata directly inside the unused high-order bits of the 64-bit object reference pointer:

+-------------------+-------------+-----------------------------------------------+
| 16 Unused Bits | 4 Color Bits| 44-bit Object Offset (Addresses up to 16 TB) |
+-------------------+-------------+-----------------------------------------------+
| | | |
| | | +-- Finalizable (Weak/Phantom reference tracking)
| | +---- Remapped (Address points to new relocated location)
| +------ Marked1 (Active live marking phase)
+-------- Marked0 (Alternate live marking phase)
  • OS Virtual Memory Multi-Mapping (mmap): The Linux kernel maps the same physical memory page to three separate virtual memory addresses (Marked0, Marked1, and Remapped). When the CPU dereferences a colored pointer, it hits the exact same physical heap page regardless of which color bit is active, avoiding software bitmasking penalties.

Generational ZGC (JEP 439 - Java 21 LTS)

In Java 21, Generational ZGC (-XX:+UseZGC -XX:+ZGenerational) separated the ZGC heap into Young and Old generations:

  • Young collections run frequently and collect 90%+ of short-lived objects with almost zero CPU overhead.
  • Resolves the legacy ZGC "Allocation Stall" issue where high allocation rates outpaced the single-generation concurrent marking cycle.
  • Delivers consistent p99.99 latencies under 1 millisecond while maintaining throughput comparable to G1 GC.

9. Flags Cheatsheet

FlagMeaning
-Xms / -XmxHeap size (keep headroom for non-heap RSS in containers)
-Xmn / -XX:NewRatioYoung size
-XX:SurvivorRatioEden vs each Survivor (default 8 β†’ ~8:1:1)
-XX:MaxTenuringThresholdMax age before promotion (default 15)
-XX:+UseG1GCG1 (default JDK 9+)
-XX:MaxGCPauseMillisG1 pause goal (soft, default 200ms)
-XX:InitiatingHeapOccupancyPercentWhen G1 starts concurrent mark (default 45%)
-XX:+UseZGC / -XX:+ZGenerationalGenerational ZGC (sub-millisecond pauses on JDK 21+)
-Xlog:gc*,gc+phases=debug:file=gc.log:time,uptime,pid:filecount=5,filesize=100MProduction Unified GC logging

10. Interview Hooks

  • Explain S0/S1 From/To flip and why one survivor is empty after a young GC.
  • Parallel vs concurrent: Parallel = many GC threads but STW; concurrent = mutators run during mark/relocate.
  • Why Mark-Copy for Young and why whole-heap copy is a bad Old strategy.
  • Tri-color marking: How write barriers (SATB) prevent premature reclamation of live objects.
  • ZGC Colored Pointers & Load Barriers: How self-healing pointers achieve sub-millisecond pauses without Stop-The-World relocation phases.
  • When to stay on G1 (maximum batch throughput) vs move to Generational ZGC (strict <1ms SLA requirements).

πŸ“–
Track Page Progress0 / 635 Read
Knowledge Base Completion0%