Heap vs Stack Memory in the JVM — What Lives Where, Lifetime, and OOM vs StackOverflow
Fast recall
Quick revision
Core answer
-Xmx can be GBs), managed by garbage collector. Primitives on the stack (as locals) or in the heap (as fields). Object references live on the stack; the object itself lives on the heap. `StackOverflowError` = recursion / call chain too deep for the stack. `OutOfMemoryError` = heap exhausted, can't allocate new objects. Modern JVM also has metaspace (class metadata), direct memory (NIO buffers), and thread-local allocation buffers (TLABs) within the heap for lock-free allocation.Whether the candidate knows precisely what goes on each, understands that references are on the stack but objects on the heap, and can distinguish `StackOverflowError` from `OutOfMemoryError` including their typical causes
Claiming objects are on the stack (never — unless escape analysis optimizes them away). Confusing the stack with the JVM stack vs OS stack. Not knowing about metaspace (replaced PermGen in Java 8)
Mention escape analysis + scalar replacement as the one case where objects can effectively land 'on the stack.' Explain TLABs for lock-free allocation and why `-Xss` matters for thread count. Know that direct ByteBuffers bypass the heap
Interview-ready guide
Interview answer
The JVM splits memory into distinct regions — stack and heap are the two that most directly affect the code you write.
Stack — per-thread, automatic
- Every thread gets its own stack, a LIFO of frames for each active method call
- Each frame holds local primitives, object references, and bookkeeping
- Reclaimed automatically on method return — no GC involvement
- Small — default 512KB to 1MB via
-Xss
Heap — shared, GC-managed
- Every object and array lives here, shared across all threads
- Sized by
-Xms/-Xmx; GC-managed - Allocation is fast (usually via thread-local allocation buffers — TLABs)
The classic distinction
- Object references live on the stack
- The objects themselves live on the heap
- Primitive locals live on the stack
- Primitive fields inside objects live on the heap inside the object
Failure modes
StackOverflowError= thread's stack ran out of frames, almost always unbounded recursionOutOfMemoryError: Java heap space= heap is full and GC can't free enough — typically a memory leak or an undersized heapOutOfMemoryError: Metaspace= too many classes loaded, common in long-running app servers with leaking classloadersOutOfMemoryError: Direct buffer memory= leaked NIO direct buffers
Modern nuances
- The JIT's escape analysis + scalar replacement can put fields of non-escaping objects directly in the stack frame — an optimization, not a language guarantee
- Virtual threads (Java 21) store their stacks on the heap, decoupling thread count from
-Xss - Direct memory (NIO
ByteBuffer.allocateDirect) lives outside the Java heap in OS memory
Recommendation: For most server applications, you rarely need to tune -Xss — default 1MB is fine. Focus on `-Xmx` and GC choice (G1 is modern default; ZGC or Shenandoah for low-latency) and use heap dumps + a tool like MAT or VisualVM to diagnose OutOfMemoryError. If you see StackOverflowError, look for unbounded recursion before touching -Xss.
Heap vs Stack Memory in the JVM — What Lives Where, Lifetime, and OOM vs StackOverflow
Direct Answer
Stack = per-thread, stores frames for each method call (local primitives, object references, return addresses). Small (default ~512KB – 1MB), automatically reclaimed on method return, thread-local. Heap = shared across all threads, stores all objects and arrays. Large (-Xmx can be GBs), managed by garbage collector. Primitives on the stack (as locals) or in the heap (as fields). Object references live on the stack; the object itself lives on the heap. StackOverflowError = recursion / call chain too deep for the stack. OutOfMemoryError = heap exhausted, can't allocate new objects. Modern JVM also has metaspace (class metadata), direct memory (NIO buffers), and thread-local allocation buffers (TLABs) within the heap for lock-free allocation.
Common Mistakes & Pitfalls
Claiming objects are on the stack (never — unless escape analysis optimizes them away). Confusing the stack with the JVM stack vs OS stack. Not knowing about metaspace (replaced PermGen in Java 8)
Check your understanding
Answer these without looking back at the article.
- What is escape analysis and how does it let the JIT effectively put objects on the stack?
- Why did Java 8 replace PermGen with Metaspace, and what changed?
- How do thread-local allocation buffers (TLABs) make heap allocation fast under multi-threaded load?
- What's different about virtual threads' stacks in Java 21 compared to platform thread stacks?
- When would you tune `-Xss`, and what's the trade-off with the maximum number of concurrent threads?
Related interview prep categories
1Looking for a structured roadmap?
Every module on this page is also part of the full Java backend interview track.