🧠 JVM Internals — Memory Model, Heap, Stack and Garbage Collection
Master JVM internals — heap vs stack, the JVM memory model, garbage collection (generational GC, G1, ZGC), class loading, JIT compilation and memory leaks in Java. With interview Q&A.
Understanding the JVM separates senior Java engineers from the rest. It manages memory so you don't call free() — but you must understand how.
🗄️ Runtime memory areas
- Heap — all objects live here, shared across threads. Garbage-collected.
- Stack — one per thread; holds method frames, local variables, and references. Auto-freed when a method returns.
- Metaspace — class metadata (replaced PermGen in Java 8).
- PC register & native stack — per-thread execution bookkeeping.
♻️ Garbage collection
The GC reclaims objects no longer reachable from roots (stack variables, statics). Java uses generational GC:
- Young generation (Eden + survivor spaces) — new objects; minor GC is fast and frequent.
- Old generation — long-lived objects; major GC is slower.
Most objects die young — the generational hypothesis makes GC efficient.
⚙️ GC algorithms
- G1 GC — default since Java 9; low-pause, region-based.
- ZGC / Shenandoah — ultra-low-pause (sub-millisecond) for huge heaps.
- Serial / Parallel — simpler, throughput-focused.
🔥 JIT compilation
The Just-In-Time compiler watches running bytecode and compiles hot methods to optimized native code — why long-running Java is fast.
🚰 Memory leaks in Java?
Yes — GC only collects unreachable objects. Leaks happen when you unintentionally keep references (static collections that grow forever, unclosed resources, listeners never removed).
💻 Code Examples
Stack vs heap
void demo() {
int x = 5; // x on the stack
int[] arr = new int[1000]; // 'arr' ref on stack, array on heap
} // x and arr ref popped; array eligible for GCLocals live on the stack; objects live on the heap.
Eligible for garbage collection
StringBuilder sb = new StringBuilder("data");
sb = null; // the old StringBuilder is now unreachable -> GC eligible
System.gc(); // a suggestion, not a guaranteeNulling the only reference makes the object collectable.
A classic memory leak
static final List<byte[]> CACHE = new ArrayList<>();
void handle() {
CACHE.add(new byte[1_000_000]); // never removed -> grows forever
}Static collection that only grows = memory leak.
⚠️ Common Mistakes
- Believing Java can't leak memory — it can, via lingering references (growing static collections, unremoved listeners).
- Calling System.gc() expecting immediate collection — it's only a hint; the JVM decides.
- Confusing stack and heap — local primitives/references are on the stack; objects are always on the heap.
- Tuning GC flags blindly — measure with a profiler first; the default G1 is good for most apps.
🎯 Interview Questions
Real questions asked at top product and service-based companies.
Q1.What's the difference between heap and stack memory?Beginner
Q2.How does garbage collection work in Java?Intermediate
Q3.What is the generational hypothesis?Intermediate
Q4.Can a Java application have a memory leak?Advanced
Q5.What does the JIT compiler do?Advanced
🧠 Quick Summary
- Heap = objects (GC'd, shared); stack = per-thread frames/locals.
- Generational GC: young gen (frequent minor GC) + old gen (rare major GC).
- G1 is the default; ZGC/Shenandoah for ultra-low pause.
- JIT compiles hot bytecode to native code at runtime.
- Java CAN leak memory via lingering references; System.gc() is only a hint.