2. Memory & Garbage Collection

JVM Memory Regions & Garbage Collection Tuning

In-depth engineering breakdown of JVM memory layout (Heap, Stack, Metaspace), Object Lifecycle, Weak Generational Hypothesis, G1GC vs ZGC collectors, and GC tuning.

🧠 JVM Runtime Memory Data Areas Layout

The JVM splits process memory into Thread-Shared regions (accessible by all threads) and Thread-Private regions (dedicated per thread):

  • Analogy: Warehouse Storage Rooms & Worker Workbenches.
    • Heap Memory (Shared): The central warehouse floor where large storage crates (Objects) are placed.
    • Thread Stack Frames (Private): The personal clipboard workbench carried by each worker thread containing active method variables.
    • Metaspace (Shared): The filing cabinet holding master structural architectural blueprints (Class metadata).
    • Program Counter (PC) Register (Private): The worker's current step checklist pointer.
                           JVM Memory Data Areas
                                     β”‚
        β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
        β–Ό                                                         β–Ό
  Thread-Shared Regions                                  Thread-Private Regions
  (Heap Memory & Metaspace)                              (Java Stack, PC, Native Stack)
                        JVM Heap Generation Structure
                                     β”‚
   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
   β–Ό                                                                   β–Ό
Young Generation (Short-Lived Objects)               Old / Tenured Generation (Long-Lived Objects)
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”        β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Eden Space (New Objs) β”‚ Survivorβ”‚ Survivorβ”‚        β”‚ Survived N Minor GCs                      β”‚
β”‚                       β”‚ S0      β”‚ S1      β”‚        β”‚ Promoted Objects & Caches                 β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜        β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

🐣 Object Lifecycle & The Weak Generational Hypothesis

The Weak Generational Hypothesis states that most instantiated objects die shortly after creation (local variables inside methods).

  1. Eden Space Allocation: New objects are allocated in the Eden space.
  2. Minor GC: When Eden fills up, a fast Minor GC runs. Live objects are copied to Survivor space S0 (age counter set to 1), and dead objects are reclaimed.
  3. Survivor Ping-Pong: Subsequent Minor GCs copy live objects back and forth between S0 and S1, incrementing their age counter.
  4. Promotion to Old Gen: When an object survives $N$ Minor GC cycles (default threshold -XX:MaxTenuringThreshold=15), it is promoted to the Old (Tenured) Generation.

🧹 Modern Garbage Collector Suite: G1GC vs. ZGC

CollectorAlgorithm StrategyTarget Pause TimeBest ForDefault Status
Serial GC (-XX:+UseSerialGC)Single-threaded Mark-Sweep-CompactHigh pause timesSingle-CPU embedded devices / CLI scriptsLegacy
Parallel GC (-XX:+UseParallelGC)Multi-threaded throughput focusedTens to hundreds of msHigh-throughput batch processing jobsDefault Java 8
G1GC (-XX:+UseG1GC)Region-based incremental concurrentPredictable (< 200 ms)General enterprise web applicationsDefault Java 9+
ZGC (-XX:+UseZGC)Colored Pointers & Load BarriersSub-millisecond (< 1 ms)Ultra-low latency enterprise microservicesProduction Ready Java 15+
// Inspecting Heap Memory Programmatically in Java
public class MemoryDiagnostic {
    public static void main(String[] args) {
        Runtime runtime = Runtime.getRuntime();
        long maxMemory   = runtime.maxMemory() / (1024 * 1024);
        long totalMemory = runtime.totalMemory() / (1024 * 1024);
        long freeMemory  = runtime.freeMemory() / (1024 * 1024);

        System.out.println("Max Heap (-Xmx):   " + maxMemory + " MB");
        System.out.println("Allocated Heap:    " + totalMemory + " MB");
        System.out.println("Free Heap Space:   " + freeMemory + " MB");
    }
}

βš™οΈ Essential Production GC Tuning Flags

# Set initial heap (-Xms) and maximum heap (-Xmx) to identical values to avoid resizing overhead
java -Xms4g -Xmx4g -XX:+UseG1GC -XX:MaxGCPauseMillis=200 -jar app.jar

# Enabling Ultra-Low Latency ZGC in Java 21+
java -Xms8g -Xmx8g -XX:+UseZGC -XX:+ZGenerational -jar high-frequency-app.jar

❓ Conceptual Quizzes

Knowledge Check

What is the Weak Generational Hypothesis in JVM memory management?

Knowledge Check

Why does ZGC achieve sub-millisecond Garbage Collection pause times even on multi-terabyte heaps?


πŸ’» Practice Problems

Problem: Garbage Collection Memory Heap Diagnostic Tool

Write a Java utility program that calculates used heap memory before and after creating 500,000 temporary string objects, and triggers System.gc() to observe heap reclamation.

On this page