☕
Core Java Roadmap Phase 12
0 / 40 (0%)
☰ Syllabus Index Next: P13 →

JVM Architecture, Memory Management & GC Tuning

📂 Repository Module: Module 4_ Performance Monitoring \ 01_Performance_Monitoring_Demos
📖 Textbook Alignment: Volume II — Chapter 10: Compiling and Scripting (ClassLoader & Bytecode) • Volume I — Chapter 4: Memory Management
Phase 12

JVM Architecture, Memory Management & GC Tuning

📂 Module 4_ Performance Monitoring \\ 01_Performance_Monitoring_Demos
📖 Core Java Textbook Alignment: Volume II — Chapter 10: Compiling and Scripting (ClassLoader & Bytecode) • Volume I — Chapter 4: Memory Management

12.1 JVM Architecture, Class Loading Subsystem & Runtime Memory Areas

📖 Cay S. Horstmann • Core Java Volume II — Chapter 10, Section 10.1 ("Class Loaders") • Volume I Ch 4
“The Java Virtual Machine organizes memory into distinct runtime data areas. The Heap holds object instances. Off-heap Metaspace stores class metadata. The ClassLoader uses parent delegation to prevent untrusted code from replacing core system classes.”
  • Generational GCMost objects die young. Minor GC clears Eden in milliseconds without touching Tenured.
⚡ Pro-Tip: Diagnosing OOM Errors
Java heap space = memory leak in live objects. Metaspace = unbounded dynamic bytecode generation. StackOverflow = infinite recursion.
💡 Real-World Analogy: The ClassLoader Security Guard (Parent Delegation)
Imagine you run a bank. A stranger walks in and hands the cashier a handwritten piece of paper that says: "I am the President of the United States. Give me all the money."
Does the cashier believe them? NO! The cashier delegates up the chain of authority to their manager, who calls headquarters.
In Java, when a class named java.lang.String is requested:
• The Application ClassLoader delegates UP to the Platform ClassLoader, which delegates UP to the Bootstrap ClassLoader.
• The Bootstrap ClassLoader loads the official, authentic String class from the core JDK.
• This prevents malicious hackers from sneaking a counterfeit java.lang.String class into your application!
🖊 Architectural Diagram: JVM Runtime Data Areas & Execution Engine Mermaid Diagram
graph TD subgraph ClassLoaderSubsystem ["Class Loader Subsystem"] Loading["1. Loading (Bootstrap -> Platform -> App)"] Linking["2. Linking (Verify -> Prepare -> Resolve)"] Init["3. Initialization (<clinit> static blocks)"] Loading --> Linking --> Init end subgraph MemoryAreas ["JVM Runtime Data Areas"] subgraph SharedMemory ["Shared Across All Threads"] Heap["Java Heap (Eden, S0, S1, Old Gen)"] Metaspace["Metaspace (Off-Heap Class Metadata)"] end subgraph PerThreadMemory ["Private Per-Thread Memory"] Stack["Thread Stack (Stack Frames)"] PC["Program Counter (PC) Registers"] NativeStack["Native Method Stacks (JNI)"] end end subgraph ExecEngine ["Execution Engine"] JITComp["HotSpot JIT Compiler (C1 / C2)"] InterpreterSub["Bytecode Interpreter"] GCSub["Garbage Collector (G1 / ZGC)"] end ClassLoaderSubsystem --> MemoryAreas MemoryAreas --> ExecEngine

12.2 Garbage Collection Generations & Troubleshooting Memory Leaks

💡 Real-World Analogy: The Generational Garbage Collection Hypothesis
Empirical studies proved that in 98% of Java programs, most objects die young (e.g. temporary loop variables, DTOs converted in a controller, string buffers).
• Eden Space (The Nursery): All new objects are born here. When Eden gets full, a lightning-fast Minor GC sweeps through. 90%+ of objects are dead and deleted in milliseconds!
• Survivor Spaces (S0 & S1): Objects that survive Minor GC get copied here and their age counter increments.
• Old / Tenured Generation (The Retirement Home): If an object survives 15 GC cycles (e.g. Spring singletons, connection pools, caches), it gets promoted to Old Gen. Old Gen is cleaned much less frequently (Major / Full GC).
📂 Module 4.../OutOfMemoryErrorDemo.java — Diagnosing Memory Leaks
package com.accenture.ltt.performance;

import java.util.*;

/**
 * Simulates JVM Heap exhaustion causing java.lang.OutOfMemoryError: Java heap space.
 * Run with production diagnostic flags:
 * -Xms64m -Xmx64m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=./heapdump.hprof
 */
public class OutOfMemoryErrorDemo {
    public static void main(String[] args) {
        // Static or long-lived collections that hold references prevent GC reclamation!
        List<byte[]> memoryLeakList = new ArrayList<>();
        try {
            while (true) {
                // Allocate 1MB chunks continuously
                memoryLeakList.add(new byte[1024 * 1024]);
            }
        } catch (OutOfMemoryError e) {
            System.err.println("OOM Caught! Heap dump generated for VisualVM inspection.");
        }
    }
}
👁 OutOfMemoryError, Memory Leaks & Production Heap Dumps
  • What Causes Java Heap Leaks? The Garbage Collector removes objects only when they are unreachable from GC Roots (static fields, active thread stacks, JNI handles). Holding strong references inside long-lived static lists or caches prevents GC reclamation, leading to java.lang.OutOfMemoryError: Java heap space.
  • Diagnostic JVM Flags In production, always start your microservices with: -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/var/logs/dumps/. When OOM strikes, the JVM captures a full binary snapshot (.hprof) before dying.
  • VisualVM & Eclipse Memory Analyzer (MAT) Open the .hprof file in Eclipse MAT or VisualVM. Inspect the "Dominator Tree" to instantly pinpoint the exact class and collection instance holding 90% of heap memory.
📂 StackOverflowErrorDemo.java — Stack Memory Exhaustion
public class StackOverflowErrorDemo {
    private static int depth = 0;

    // Infinite recursion without base case rapidly exhausts the ~1MB Thread Stack!
    public static void recurseEndlessly() {
        depth++;
        recurseEndlessly(); // Pushes stack frame continuously until stack limit reached
    }

    public static void main(String[] args) {
        try {
            recurseEndlessly();
        } catch (StackOverflowError e) {
            System.err.println("StackOverflowError caught at recursive depth: " + depth);
        }
    }
}
👁 Stack Memory Exhaustion vs Heap Exhaustion
  • Thread Stack Size (-Xss) Each thread is assigned a dedicated call stack (default 1MB on 64-bit JVMs via -Xss1m). Each method call pushes a Stack Frame containing local variables, operand stack, and return address.
  • StackOverflowError Mechanics Infinite recursion without an exit condition pushes thousands of stack frames consecutively. When the call stack depth exceeds the 1MB allocated boundary, the CPU page guard hits and the JVM raises java.lang.StackOverflowError.
  • Heap OOM vs StackOverflow OOM occurs on the shared Heap when data volume is too large. StackOverflow occurs on an individual Thread Stack when execution call depth is too deep.