Fundamentals 18 min read

Mastering JVM Memory: From Heap to Metaspace and Beyond

This article provides a comprehensive overview of the Java Virtual Machine memory architecture, covering heap layout, object allocation, Metaspace, stack frames, native method stacks, program counters, direct memory, and code cache, complete with configuration tips and practical code examples.

Sanyou's Java Diary
Sanyou's Java Diary
Sanyou's Java Diary
Mastering JVM Memory: From Heap to Metaspace and Beyond

Preface

This JVM series is a summary of knowledge points collected during the author's learning process, aiming to help readers quickly grasp key JVM concepts. For a more systematic and detailed study, readers should consult professional books and documentation.

Article outline:

JVM memory area overview

Heap space allocation and overflow demonstration

How memory is allocated when creating a new object

Method area to Metaspace

What is a stack frame? Its contents and understanding

Native method stack

Program Counter

Code Cache

Note: Distinguish between JVM memory structure (layout) and JMM (Java Memory Model)!

Overview

Memory is a crucial system resource that acts as a bridge between disk and CPU, supporting the real‑time execution of OS and applications. The JVM memory layout defines how Java requests, allocates, and manages memory, ensuring efficient and stable operation.

The above diagram shows a classic Java memory layout (the heap area is drawn smaller than it actually is).

If we classify by whether threads share the area, the following diagram applies:

Understanding whether an area is thread‑shared becomes natural once you know the purpose of each region; no need for rote memorization.

Now let's explore each region.

Heap

1. Introduction

The heap is the primary region where OutOfMemoryError occurs. It is the largest memory area, shared by all threads, storing almost all object instances and arrays. With JIT compilation and escape analysis, stack allocation and scalar replacement can reduce heap allocations.

Related topic: Escape analysis in JIT compilation – see “Deep Understanding of Java Escape Analysis”.

The Java heap is managed by the garbage collector and is divided into generations: young and old. The young generation includes Eden, From Survivor, and To Survivor spaces. Thread‑local allocation buffers (TLAB) may also exist.

2. Adjustment

The heap can be physically non‑contiguous as long as it is logically contiguous. It can be fixed‑size or dynamically resized at runtime.

How to adjust?

Set parameters such as -Xms256M -Xmx1024M to define initial and maximum heap size. In production, Xms and Xmx are often set equal to avoid heap resizing overhead after GC.

3. Default allocation

Typical default ratios: InitialSurvivorRatio=8, NewRatio=2. With a 40 MB Eden, each Survivor is 5 MB, young generation totals 50 MB, old generation 100 MB, making the heap 150 MB.

<code>java -XX:+PrintFlagsFinal -version</code>

Relevant flags:

-XX:InitialSurvivorRatio – initial Eden/Survivor ratio

-XX:NewRatio – Old/Young memory ratio

4. Heap overflow demo

<code>/*** VM Args:-Xms10m -Xmx10m -XX:+HeapDumpOnOutOfMemoryError */
public class HeapOOMTest {
    public static final int _1MB = 1024 * 1024;
    public static void main(String[] args) {
        List<byte[]> byteList = new ArrayList<>(10);
        for (int i = 0; i < 10; i++) {
            byte[] bytes = new byte[2 * _1MB];
            byteList.add(bytes);
        }
    }
}
</code>
<code>java.lang.OutOfMemoryError: Java heap space
Dumping heap to java_pid32372.hprof ...
</code>

The flag -XX:+HeapDumpOnOutOfMemoryError causes the JVM to output heap information when an OOM occurs.

Object allocation process

Most objects are created in Eden; when Eden fills, a Young GC (YGC) occurs. Live objects are moved to Survivor spaces, which swap roles each GC. Objects that exceed Survivor capacity are promoted to the old generation. The -XX:MaxTenuringThreshold controls promotion after a number of YGCs (default 15).

For more on GC terminology, see the GC chapter of this series.

Metaspace

In HotSpot, the former Permanent Generation (method area) stored class metadata and the constant pool. PermGen caused frequent OOM errors, so Java 8 replaced it with Metaspace, which resides in native memory and is limited only by the host’s memory.

Key JVM options:

-XX:MetaspaceSize – initial size

-XX:MaxMetaspaceSize – maximum size (no default limit)

-XX:MinMetaspaceFreeRatio

-XX:MaxMetaspaceFreeRatio

Java Virtual Machine Stack

Each thread has its own JVM stack, which stores stack frames. A stack frame contains the local variable table, operand stack, dynamic linking information, and the return address.

1. Local variable table

Allocated at compile time; its size does not change at runtime.

<code>public int test(int a, int b) {
    Object obj = new Object();
    return a + b;
}
</code>

2. Operand stack

Used by the stack‑based execution engine. Example:

<code>public class OperandStackTest {
    public int sum(int a, int b) {
        return a + b;
    }
}
</code>

Disassembled bytecode shows a stack depth of 2 and locals of 3.

3. Dynamic linking

Each frame holds a reference to the method’s constant‑pool entry for dynamic linking.

4. Return address

Methods may exit normally (RETURN, IRETURN, etc.) or via exception; the return address is restored accordingly.

Native Method Stack

Serves native methods similarly to the JVM stack; some JVMs combine the two.

Program Counter

A small thread‑private memory that records the current bytecode line number, enabling the CPU to resume execution after thread switches.

Direct Memory

Not part of the JVM runtime data area, but used via NIO’s DirectByteBuffer . It resides outside the Java heap and is limited by the host’s physical memory.

Code Cache

The region where the JVM stores compiled native code (nmethods). The JIT compiler is the main consumer of this cache.

References

《深入理解Java虚拟机》 – 周志明

《码出高效》

Metaspace in Java 8

JVM instruction set illustration

Introduction to JVM Code Cache

JavaJVMMemory ManagementGarbage CollectionHeapMetaspace
Sanyou's Java Diary
Written by

Sanyou's Java Diary

Passionate about technology, though not great at solving problems; eager to share, never tire of learning!

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.