skip to content

Bridge: JVM Platform Internals

An orientation pointer: the runtime memory areas, GC algorithms, reachability, class loading and JIT that all of this sits on are language-neutral JVM platform topics covered under lang-jvm. Study them alongside these Java APIs — interview questions routinely cross the line between the two.

part ofJavaoverview, primer and where to startread it →
on this pageshow

questions

6

What are the main runtime memory areas the JVM divides memory into, and which are shared across threads versus per-thread?

level: juniorimportance: must knowfreq 72%

answer

  1. Heap = shared, objects; Stack = per-thread, frames
  2. Metaspace = class metadata, native memory, replaced PermGen in Java 8
  3. PC register + native stack also per-thread
  4. OOM: heap space vs Metaspace; StackOverflow vs OutOfMemory

basics

~20 s

The JVM splits memory into the heap (where objects live, shared by all threads), the stacks (one per thread, holding method calls and local variables), and metaspace (class metadata). The heap is where garbage collection happens.

solid answer

~40 s

The JVM organizes memory into a few runtime data areas. The heap is a single shared region where all objects and arrays are allocated and where the garbage collector operates; modern HotSpot splits it into generations (young + old). Each thread gets its own JVM stack, made of frames pushed per method call, holding local variables, operand stack, and the return address; this is where StackOverflowError comes from. The program counter (PC) register is also per-thread, tracking the current bytecode instruction. Metaspace (native memory, since Java 8 replacing PermGen) holds class metadata such as method bytecode and field layouts. There is also a native method stack for JNI calls. The key split: heap and metaspace are shared; stacks and PC registers are per-thread, which is why thread-local data needs no synchronization.

go deeper

for a junior

Can name heap (objects), stack (method calls/locals), and that the heap is where GC works; knows objects go on the heap.

for a middle

Explains the shared-vs-per-thread split, what a stack frame holds, and distinguishes StackOverflowError from OutOfMemoryError with their causes.

for a senior

Adds Metaspace vs PermGen history, generational heap layout, PC register and native stack, and ties the split to why local data needs no synchronization.

for a principal

Reasons about sizing (heap, Metaspace, thread-stack -Xss) trade-offs, off-heap memory, classloader leaks filling Metaspace, and how memory-area layout informs container memory limits and OOM diagnostics.

## What "runtime memory areas" means The **JVM (Java Virtual Machine)** is the runtime that executes your compiled Java (bytecode). When it runs, it carves the memory the operating system gives it into distinct **runtime data areas**, each with a specific job. Knowing these areas explains where objects live, why some errors happen, and how garbage collection works. ## The areas, one by one ### 1. Heap (shared) The **heap** is one big region shared by every thread. **Every object and array you create with `new` lives here.** Because it is shared, two threads can both reference the same object — which is exactly why you need synchronization for shared mutable state. The heap is the *only* area the **garbage collector (GC)** manages: GC is the automatic process that reclaims memory of objects no longer in use. HotSpot (the standard JVM) further divides the heap into **generations** — a **young generation** for newly created, short-lived objects, and an **old (tenured) generation** for objects that survive long enough. Running out of heap throws `OutOfMemoryError: Java heap space`. ### 2. JVM stacks (per-thread) Each thread has its **own stack**. Every time a method is called, a **stack frame** is pushed onto that thread's stack; when the method returns, the frame is popped. A frame holds: - **Local variables** (including method parameters and `this`), - The **operand stack** (scratch space the bytecode uses to compute expressions), - A reference to the constant pool / return information. Important: a frame stores **primitives by value** and **objects by reference** (the object itself is on the heap; only the pointer is on the stack). Because each thread has its own stack, stack data is implicitly thread-safe. Infinite or too-deep recursion exhausts the stack → `StackOverflowError`. ### 3. Program Counter (PC) register (per-thread) A tiny per-thread register holding the address of the **bytecode instruction currently executing**. It lets the JVM resume the right spot after a thread is paused. ### 4. Metaspace (shared, native memory) **Metaspace** stores **class metadata**: the loaded class's structure — its methods' bytecode, field names and types, the runtime constant pool, etc. It is *not* the heap; it lives in **native (off-heap) memory** sized by the OS. Before Java 8 this was the fixed-size **PermGen (Permanent Generation)**, which was a frequent source of `OutOfMemoryError: PermGen space`. Java 8 replaced it with Metaspace, which auto-grows (bounded by `-XX:MaxMetaspaceSize`); exhausting it throws `OutOfMemoryError: Metaspace`. ### 5. Native method stack (per-thread) Used when Java calls **native (C/C++) code** via **JNI (Java Native Interface)**. ## The shared-vs-per-thread split (the headline) | Area | Scope | Holds | |---|---|---| | Heap | **Shared** | objects, arrays | | Metaspace | **Shared** | class metadata | | JVM stack | **Per-thread** | frames: locals, operand stack | | PC register | **Per-thread** | current instruction | | Native stack | **Per-thread** | native-call state | This split is the whole reason **local variables never need locking but heap objects do**. ## Why this matters for the Java APIs in this topic Reference types (`SoftReference`/`WeakReference`/`PhantomReference`), `Cleaner`, and `OutOfMemoryError` diagnostics all operate on **heap** objects and the GC that manages them. You cannot reason about "will this object be collected" without knowing it lives on the shared heap and is reached (or not) from thread stacks and static fields — the **GC roots**.

  • Why was PermGen replaced by Metaspace in Java 8?
    PermGen had a fixed, hard-to-size limit living in the heap, causing frequent OutOfMemoryError: PermGen space (especially with many classloaders/redeploys). Metaspace moves class metadata to auto-growing native memory, removing the fixed cap by default and tying it to OS memory instead.
  • Where does a local primitive int versus a local object reference get stored?
    Both sit in the current stack frame's local-variable slots. The int's value is stored inline; for an object, only the reference (pointer) is in the frame — the object itself is allocated on the heap.

saying these in an interview costs you the question

  • Saying objects live on the stack — only references/primitives sit in frames; objects are on the heap
  • Calling Metaspace part of the heap (it is off-heap native memory)
  • Thinking each thread has its own heap
  • Confusing StackOverflowError (stack exhausted) with OutOfMemoryError (heap/metaspace exhausted)

context

open as a page

How does the JVM decide an object is garbage? Explain reachability and GC roots.

level: middleimportance: must knowfreq 78%

basics

~20 s

An object is garbage when it can no longer be reached by following references from "GC roots" (like local variables and static fields). The collector keeps reachable objects and frees the rest. It is not based on reference counting.

open as a page

Explain generational garbage collection and the weak generational hypothesis. How do minor and major collections differ?

level: middleimportance: should knowfreq 66%

basics

~20 s

Most objects die young, so the heap is split into a young generation (new objects) and an old generation (survivors). A minor GC collects only the young area (fast, frequent); a major/full GC handles the old area (slower, rarer). Objects that survive get promoted to the old generation.

open as a page

What is java.lang.ref.Cleaner, why does it replace finalize(), and how do you use it correctly?

level: seniorimportance: should knowfreq 52%

basics

~20 s

Cleaner runs a cleanup action after an object becomes unreachable, using phantom references and a background thread. It replaces finalize(), which was unreliable and is deprecated. The key rule: the cleanup action must not reference the object it cleans up.

open as a page

How do you diagnose an OutOfMemoryError in production? Distinguish the common OOM kinds and the tools you'd use.

level: seniorimportance: should knowfreq 60%

basics

~20 s

Read the OutOfMemoryError message — it tells you which kind: heap space, Metaspace, GC overhead limit, or unable to create native thread. Capture a heap dump (-XX:+HeapDumpOnOutOfMemoryError), open it in a tool like Eclipse MAT, and find what's holding the most memory.

open as a page

Explain the reachability ladder in java.lang.ref: strong, soft, weak, and phantom references — and when you'd use each.

level: seniorimportance: should knowfreq 64%

basics

~20 s

A normal (strong) reference keeps an object alive. SoftReference lets the GC drop the object only when memory is low (good for caches). WeakReference lets it be collected as soon as nothing strong points to it (good for canonicalizing maps). PhantomReference signals after collection, for cleanup.

open as a page