G1 Garbage Collector: Regions, SATB & Pause Prediction
The Garbage-First (G1) Garbage Collector is the default general-purpose collector in HotSpot since Java 9. Designed for multi-core processors with multi-gigabyte heaps, G1 achieves predictable pause times by partitioning the physical heap into thousands of equal-sized regions and prioritizing the reclamation of regions containing the most garbage ("Garbage-First").
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.
1. G1 Region Architecture
Unlike legacy generational collectors (Serial, Parallel, CMS) that allocated large contiguous physical memory blocks for Eden, Survivor, and Old generations, G1 subdivides the heap into approximately 2,048 equal-sized regions (ranging from 1MB to 32MB based on total heap size):
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β G1 REGION TOPOLOGY (Non-Contiguous Generational Assignment) β
β β
β [E] [O] [S] [E] [F] [O] [H] [H] [E] [S] [O] [F] [E] [O] [F] [O] β
β β
β β’ E: Eden Region (Dynamically expanded during allocation bursts) β
β β’ S: Survivor Region (Holds objects surviving Minor GC) β
β β’ O: Old Region (Tenured objects surviving tenuring threshold) β
β β’ H: Humongous Region (Objects >= 50% of standard region size) β
β β’ F: Free Region (Uncommitted memory waiting for allocation) β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Humongous Objects & Fragmentation Traps
- An object whose size exceeds 50% of a G1 region is classified as Humongous.
- Humongous objects bypass Eden and are allocated directly into a contiguous sequence of Old regions.
- The Performance Trap: If a G1 region is 4MB, allocating an array of 2.1MB occupies an entire 4MB region, immediately wasting 1.9MB of un-allocatable internal memory fragmentation. Repeated humongous allocations can prematurely trigger Stop-The-World
Pause Full(Full GC). - Tuning Fix: Increase region size via
-XX:G1HeapRegionSize=16mor-XX:G1HeapRegionSize=32mso large buffers fit into standard regions.
2. Remembered Sets (R-Sets) & Card Tables
To collect a Young region without scanning the entire Old generation to find inbound pointers, G1 maintains Remembered Sets (R-Sets) and a Card Table:
[Old Generation Region]
βββ Card (512 Bytes of Heap) βββΊ Contains pointer to Eden Object
β
βΌ
[Card Table: Marked "DIRTY" by Post-Write Barrier]
β
βΌ
[Eden Region Remembered Set (R-Set)] βββΊ Tracks pointing Card address
- Card Table: A byte array where each byte represents a 512-byte slice of physical heap memory ("Card").
- Post-Write Barrier: Whenever a thread executes an object reference update (
obj.field = target), HotSpot runs a lightweight write barrier marking the corresponding Card in the Card Table as DIRTY. - Concurrent Refinement Threads: Background GC threads sweep dirty cards and update the target region's R-Set, ensuring young evacuation pauses only inspect dirty cards rather than the entire multi-gigabyte Old space.
3. Snapshot-At-The-Beginning (SATB) Write Barrier
G1 executes its Old generation marking phase concurrently with application execution. To prevent live objects from being mistakenly collected due to concurrent mutator reference overwrites, G1 enforces Snapshot-At-The-Beginning (SATB):
[Application Mutator Overwrites Reference: a.b = c]
β
βΌ
[SATB Pre-Write Barrier]
β
Logs OLD reference 'b' to per-thread SATB Buffer
β
βΌ
Guarantees that any object live at start of GC cycle
is treated as LIVE and scanned!
- Trade-Off: SATB trades floating garbage (objects that became unreferenced during marking are preserved until the next cycle) for zero STW rescan pauses.
4. G1 Collection Cycles: Young vs. Mixed GC
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β 1. Young GC (STW Pause): β
β β’ Evacuates live objects from Eden and Survivor regions into new β
β Survivor or Old regions. β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β 2. Concurrent Marking Cycle (Mutators Running): β
β β’ Triggered when Old heap exceeds InitiatingHeapOccupancyPercent (IHOP). β
β β’ Discovers live objects across Old generation without stopping threads. β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β 3. Mixed GC (STW Pause Budgeted): β
β β’ Evacuates all Young regions PLUS candidate Old regions with the β
β highest ratio of reclaimable garbage ("Garbage-First"). β
β β’ Executed over several iterative pauses to adhere to MaxGCPauseMillis. β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
5. Critical G1 Production Tuning Flags
| JVM Flag | Default Value | Architectural Purpose & Tuning Guidance |
|---|---|---|
-XX:+UseG1GC | Default (JDK 9+) | Enables the G1 Garbage Collector. |
-XX:MaxGCPauseMillis | 200 | Soft target pause time goal. Setting too low (<50ms) triggers excessive short collections and throughput collapse. |
-XX:G1HeapRegionSize | Ergonomic (1M-32M) | Explicitly sizes regions. Set to 16M or 32M for heaps >16GB to neutralize humongous fragmentation. |
-XX:InitiatingHeapOccupancyPercent | 45 | IHOP threshold. Triggers concurrent marking when Old generation reaches this percentage of total heap. |
-XX:G1ReservePercent | 10 | Reserve memory headroom (default 10%) kept empty to prevent evacuation failures. |
6. Principal Architect Review Checklist
- Full GC Elimination: Are production GC logs monitored for
Pause Full? A Full GC in G1 indicates evacuation failure and must be resolved by tuning IHOP or increasing heap headroom. - Humongous Allocation Audit: Is
-Xlog:gc*,gc+phases=debuginspected to verify that humongous allocations do not exceed 1% of total allocations? - Realistic Pause Targets: Is
-XX:MaxGCPauseMillissized realistically (typically 150msβ250ms) rather than over-optimized to 10ms, which degrades steady-state throughput? - G1ReservePercent Headroom: On bursty allocation workloads, is
G1ReservePercentraised to 15% to absorb sudden promotion spikes?
