All topics
memory management
intermediate

JVM Memory Areas

Understand where Java puts objects (heap), call frames (stack), and class metadata (metaspace) so you can diagnose OOMs.

The JVM divides memory into separate areas, and each holds a different kind of thing. Knowing which area holds what is how you read an OutOfMemoryError, because the message names the area.

Heap is a warehouse for products (objects). Stack is each worker's clipboard (per-thread locals). Metaspace is the rulebook section (class blueprints).

Key Concepts

1
The heap holds objects. Every object you create with new lives here, and every thread shares it. It is the biggest area and the one -Xmx sizes.
new-Xmx
2
Each thread has its own stack, and it holds variables, not objects. When you call a method, a frame is pushed onto that thread's stack with its local variables. When the method returns, the frame is thrown away.
3
The distinction that matters:
4
    void example() {
        int count = 5;                 // the number 5 is ON THE STACK
        String name = new String("x"); // the OBJECT is on the heap;
    }                                  // the reference to it is on the stack
5
This is why thread count is a memory decision. Each thread reserves its own stack, typically half a megabyte to a megabyte, and that memory is outside the heap.
6
  200 threads    ~200 MB
  1,000 threads  ~1 GB
  5,000 threads  ~5 GB      -- before your objects use anything
7
That is the real reason thread pools are bounded. It is also why virtual threads, added in Java 21, matter: their stacks live on the heap and grow only as needed, so a million of them is possible.
8
Metaspace holds class definitions, not objects. It sits outside the heap in native memory and, unless you cap it, grows until the operating system refuses.
9
The usual cause of it filling up is class loaders that are never released — frameworks generating classes at runtime, or an application server where each redeploy loads everything again.
10
Read the error message; it tells you where to look.
  "Java heap space"                 objects are being retained
                                    -> take a heap snapshot
  "Metaspace"                       classes are being retained
                                    -> look for class loader leaks
  "unable to create new native
    thread"                         too many threads, or an OS limit
  "Direct buffer memory"            off-heap NIO buffers not released
  StackOverflowError                a call chain too deep for the
                                    stack -- usually runaway recursion,
                                    and raising -Xmx does nothing
11
One caveat to "objects live on the heap". The JIT compiler can sometimes prove an object never escapes the method that created it, and then it may put it on the stack or remove it entirely. So the rule is true at the language level and not always true at runtime.
12
What the interviewer is probing.1. "Where do objects and local variables live?" Probing: the split. Stalls: "Objects on the heap." Moves up: objects on the shared heap, locals and references in per-thread frames.
13
2. "Heap error or metaspace error?" Probing: reading the message. Stalls: "Both mean out of memory." Moves up: retained objects versus retained classes, and where each points you.
14
3. "Why does 1,000 threads cost a gigabyte?" Probing: stack arithmetic. Stalls: "Threads are heavy." Moves up: each reserves up to a megabyte outside the heap.
15
4. "What causes StackOverflowError?" Probing: telling it apart from OOM. Stalls: "Running out of memory." Moves up: a call chain deeper than the thread's stack; more heap does not help.
StackOverflowError
16
5. "Why generational collection?" Probing: the idea behind it. Stalls: "It is faster." Moves up: most objects die almost immediately, so collecting the young area often reclaims most garbage cheaply.
17
  Memory areas
18
  Area          Shared?     Holds                     OOM message
  ------------------------------------------------------------------
  Heap          all threads objects, arrays           "Java heap space"
    Eden                    new allocations
    Survivor S0/S1          minor-GC survivors
    Old gen                 promoted, long-lived      "Java heap space"
  Stack         per thread  frames: locals, operand   StackOverflowError
                            stack, return address
  Metaspace     all threads class metadata (native)   "Metaspace"
  Code cache    all threads JIT-compiled machine code "CodeCache"
  Direct/NIO    all threads off-heap ByteBuffers      "Direct buffer
                                                       memory"
19
  Thread count is a memory decision
20
    default stack per thread (-Xss)            512 KB - 1 MB
    200 threads                                ~200 MB
    1,000 threads                              ~1 GB
    5,000 threads                              ~5 GB  (before heap)
21
    -> this is why pools are bounded, and why virtual threads
       (Java 21) matter: their stacks live on the heap and grow
       on demand, so a million of them is feasible.
22
  Reading the error
    Java heap space            -> objects retained; take a heap dump
    Metaspace                  -> classes retained; check classloaders
                                  and dynamic proxy generation
    unable to create new
      native thread            -> thread count or OS ulimit
    Direct buffer memory       -> NIO buffers not released
    StackOverflowError         -> recursion depth, not heap size
23
  Key flags
    -Xmx / -Xms          max / initial heap
    -Xss                 stack size per thread
    -XX:MaxMetaspaceSize cap metaspace (unbounded by default)
    -XX:+HeapDumpOnOutOfMemoryError   always set this in production