Fundamentals 13 min read

Understanding JVM Memory Layout: Heap, Metaspace, Stacks, and Program Counter

This article explains the JVM memory architecture, covering the heap (young and old generations, Eden and Survivor spaces), Metaspace, virtual machine stacks, native method stacks, and the program counter register, while also illustrating key JVM parameters and bytecode execution with examples.

Top Architect
Top Architect
Top Architect
Understanding JVM Memory Layout: Heap, Metaspace, Stacks, and Program Counter

Memory Layout Overview

The JVM memory layout defines how Java allocates, manages, and releases memory at runtime, ensuring stable and efficient execution. Different JVM implementations may vary slightly, but the core concepts remain consistent.

Heap Area

The Heap stores all object instances and is the primary source of OutOfMemory (OOM) errors. Its size can be customized and adjusted at runtime using the -Xms (initial heap size) and -Xmx (maximum heap size) parameters. Setting -Xms and -Xmx to the same value avoids heap resizing during garbage collection, reducing server pressure.

The heap is divided into the Young (new generation) and Old (old generation) spaces. New objects are allocated in the Young generation, which consists of one Eden space and two Survivor spaces (S0 and S1). When Eden fills, a Young Garbage Collection (YGC) occurs, moving surviving objects to Survivor. After a configurable number of Survivor cycles (controlled by -XX:MaxTenuringThreshold , default 15), objects are promoted to the Old generation. If Survivor cannot accommodate an object, it is directly promoted.

If both Survivor and Eden cannot hold a large object, a Full Garbage Collection (FGC) is triggered. If the Old generation also lacks space, an OOM exception is thrown.

Metaspace

Since JDK 8, the former PermGen has been replaced by Metaspace, which resides in native memory. Class metadata, static fields, constants, and other class-level information are allocated here, allowing dynamic sizing and easier tuning compared to the fixed‑size PermGen of earlier JDK versions.

JVM Stacks (Virtual Machine Stack)

The stack is a thread‑private LIFO structure that stores stack frames for method execution. Each frame contains a local variable table, an operand stack, a dynamic linking reference, and a return address. The current stack frame is the only active one, and StackOverflowError occurs when the stack exceeds its limit.

Local Method Stack (Native Method Stack)

This thread‑private stack supports native methods invoked via JNI. It operates outside the JVM’s control, and excessive native calls can reduce JVM manageability. Out‑of‑memory errors in the native heap are reported as native heap OutOfMemory .

Program Counter Register

Each thread has its own PC register, which holds the address of the next bytecode instruction to execute. It is thread‑local, never shared, and does not cause memory‑overflow errors.

Bytecode Example

public int add() {
    int x = 10;
    int y = 20;
    int z = x + y;
    return z;
}

The corresponding bytecode demonstrates how constants are pushed onto the operand stack, stored in local variables, loaded, added, and finally returned.

JavaJVMMemory ManagementGarbage CollectionStackheapMetaspace
Top Architect
Written by

Top Architect

Top Architect focuses on sharing practical architecture knowledge, covering enterprise, system, website, large‑scale distributed, and high‑availability architectures, plus architecture adjustments using internet technologies. We welcome idea‑driven, sharing‑oriented architects to exchange and learn together.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.