Garbage Collector Classification Framework
Garbage collection implementations vary across JVM vendors and versions, with numerous collectors developed through Java's evolution. Classification can occur along multiple dimensions:
Concurrency Models
- Serial Collectors: Single-threaded operation (e.g., Serial GC). Efficient in constrained environments like client applications with small heaps due to minimal thread coordination overhead.
- Parallel Collectors: Multi-threaded throughput optimization (e.g., Parallel GC). Maximizes CPU utilization for faster collection but employs stop-the-world pauses.
- Concurrent Collectors: Overlap collection with application execution (e.g., G1, ZGC). Minimizes pause times through background processing, though some stop-the-world phases remain.
Memory Management Approaches
- Compacting Collectors: Eliminate fragmentation via object relocation (e.g., Parallel Old using mark-compact).
- Non-Compacting Collectors: Maintain free lists without relocation (e.g., CMS using mark-sweep).
- Region-Based: Divide heap into fixed-size regions (e.g., G1's 1-32MB regions).
Performance Tradeoffs
Three critical metrics form an optimization triangle where improving one often degrades another:
Throughput vs. Latency
- Throughput: Ratio of application execution time to total runtime (application + GC time). Optimized by reducing GC frequency through larger heaps or less aggressive collection.
- Pause Time: Duration of stop-the-world interruptions. Minimized through concurrent processing and region-based collection.
- Memory Footprint: Total heap consumption. Smaller heaps improve locality but increase GC frequency.
Modern applications increasingly prioritize pause time predictability, especially for interactive systems. The ideal collector balances these based on workload characteristics rather than maximizing any single metric.
Evolution of JVM Collectors
Historical Progression
- Serial (JDK 1.3): Original single-threaded collector
- Parallel (JDK 6): Throughput-focused multi-threaded collector
- CMS (JDK 1.4.2): First concurrent collector (removed in JDK 15)
- G1 (JDK 7u4): Region-based collector targeting predictable pauses
- ZGC (JDK 11): Sub-10ms pauses for multi-terabyte heaps
Modern Collector Landscape
| Collector | Best For | Key Characteristics |
|---|---|---|
| Parallel GC | Batch processing | Maximizes throughput via aggressive parallel collection |
| G1 GC | General-purpose servers | Predictable pauses through region-based collection |
| ZGC | Low-latency systems | Near-constant pause times regardless of heap size |
G1 Collector Architecture
G1 revolutionized heap management by dividing memory into fixed-size regions (1-32MB), enabling selective collection of garbage-rich regions. Key innovations include:
Region Management
- Regions dynamically switch between Eden, Survivor, and Old roles
- Humongous regions handle objects >50% of region size
- Remembered Sets track cross-region references without full scans
Collection Cycle
- Youth Collection: Stop-the-world evacuation of Eden/Survivor regions
- Concurrent Marking: Background liveness analysis triggered at 45% heap occupancy
- Mixed Collection: Evacuates both young and selected old regions based on garbage density
Example configuration for latency-sensitive applications:
// Target 100ms max pauses with 4GB heap
java -Xmx4g -XX:+UseG1GC \
-XX:MaxGCPauseMillis=100 \
-XX:G1HeapRegionSize=4m \
-XX:InitiatingHeapOccupancyPercent=35 \
MyApp
Advanced Collectors
ZGC (JDK 11+)
ZGC achieves ultra-low pauses through:
- Colored pointers for concurrent marking
- Load barriers for heap access coordination
- Multi-mapping of virtual memory spaces
Operates with consistent sub-10ms pauses regardless of heap size (tested up to 16TB). Enabled via:
java -XX:+UseZGC -Xmx16g MyApp
Shenandoah (OpenJDK 12+)
Similar goals to ZGC but uses Brooks pointers for concurrent compaction. Particularly effective for:
- Applications with high allocation rates
- Systems requiring consistent sub-50ms pauses
Collector Selection Strategy
Modern selection guidelines:
- < 100MB heaps: Serial GC (low overhead)
- Throughput-critical workloads: Parallel GC
- General server applications: G1 GC (default since JDK 9)
- Latency-sensitive systems: ZGC or Shenandoah
No universal solution exists—selection must align with specific application requirements and hardware constraints. Critical evaluation should include:
- Pause time distribution (not just averages)
- Memory footprint under sustained load
- Throughput during peak operations
GC Log Analysis Essentials
Key diagnostic parameters:
java -Xlog:gc*:file=gc.log:time \
-XX:+UseG1GC \
-XX:MaxGCPauseMillis=200 \
MyApp
Interpreting mixed collection events:
[GC pause (G1 Evacuation Pause) (mixed)
Ed: 120M(120M)->25M(120M)
Old: 800M(1000M)->750M(1000M)
Total: 920M->775M(1120M),
0.120 secs]
Indicates evacuation of young regions (Ed) and selected old regions (Old), with 120ms pause duration.
Practical Tuning Recommendations
- Avoid explicit young generation sizing with G1/ZGC—let adaptive algorithms optimize
- Set realistic pause targets (e.g., 200ms rather than 10ms) to maintain throughput
- Monitor humongous object allocation patterns with G1
- Use GC logs with tools like GCViewer for empirical analysis
Modern JVMs require less manual tuning than historical versions, but workload-specific validation remains essential.