Fundamentals 14 min read

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

This article explains the JVM memory layout, covering the heap (young and old generations), Metaspace, virtual machine stacks, native method stacks, and the program‑counter register, while describing their roles, configuration parameters and how they interact during garbage collection and method execution.

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

Memory Layout

The JVM memory layout defines how Java allocates, manages and reclaims memory at runtime, ensuring stable and efficient execution. Different JVM implementations may vary slightly, but the overall structure follows the JVM specification.

Heap (堆区)

The Heap stores all Java objects and is the primary source of OutOfMemoryError (OOM) . It is shared among all threads and is usually the largest memory region. Its size can be customized with -Xms (initial size) and -Xmx (maximum size) parameters.

Because the heap can grow dynamically, it is common to set -Xms and -Xmx to the same value in production to avoid runtime resizing overhead during garbage collection.

The heap is divided into two main areas:

Young generation (new generation) – consists of an Eden space and two Survivor spaces ( S0 and S1 ).

Old generation (tenured generation) – holds long‑lived objects.

Objects are allocated in Eden first; when Eden fills, a Young Garbage Collection ( YGC ) occurs, moving surviving objects to a Survivor space. After a configurable number of survivor cycles (controlled by -XX:MaxTenuringThreshold , default 15), objects are promoted to the old generation.

If both Eden and Survivor cannot accommodate an object, it is allocated directly in the old generation. When the old generation cannot fit, a Full Garbage Collection ( FGC ) is triggered; if it still fails, an OOM is thrown.

Metaspace (元空间)

Since JDK 8, the former PermGen has been removed and replaced by Metaspace , which is allocated in native memory rather than the heap. Class metadata, static fields, methods, constants, etc., are stored here.

Metaspace size grows automatically, but can be limited with -XX:MaxMetaspaceSize if needed.

JVM Stacks (虚拟机栈)

Each thread has its own JVM stack, which stores stack frames for method invocations. A stack frame contains a local variable table, an operand stack, a dynamic link, and a return address.

The operand stack is a LIFO structure used by bytecode instructions. For example, the following Java method and its bytecode illustrate how values are pushed onto the operand stack and stored in the local variable table:

public int add() {
int x = 10;
int y = 20;
int z = x + y;
return z;
}
0: bipush 10          // push constant 10
2: istore_1           // store to local variable 1 (x)
3: bipush 20          // push constant 20
5: istore_2           // store to local variable 2 (y)
6: iload_1            // load x onto operand stack
7: iload_2            // load y onto operand stack
8: iadd               // add top two ints, push result
9: istore_3           // store result to local variable 3 (z)
10: iload_3           // load z
11: ireturn           // return int value

When a method finishes, its frame is popped; if an exception occurs, the stack is unwound until a handler is found.

Native Method Stacks (本地方法栈)

Native method stacks are also thread‑private and are used when Java code calls native methods via the Java Native Interface (JNI). They operate outside the JVM’s memory management and can cause native heap OutOfMemory if overused.

Program Counter Register (程序计数寄存器)

Each thread has a program‑counter (PC) register that holds the address of the next bytecode instruction to execute. It is the only JVM memory area that is not subject to garbage collection and is unique per thread.

Summary

From a thread perspective, the heap and Metaspace are shared among all threads, while the JVM stack, native method stack, and PC register are thread‑local. Understanding these components helps developers tune memory parameters, avoid OOM errors, and write more efficient Java applications.

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.