A running JVM process uses several different runtime memory areas, and understanding their boundaries is essential for reading memory errors, stack traces, thread dumps, and GC behavior.

Learning Question

When people say “JVM memory,” what memory are they talking about?

The phrase “JVM memory” is often too broad. A Java application uses heap memory, per-thread stacks, class metadata memory, native memory, generated code memory, direct buffers, and operating system thread resources. These areas do not fail in the same way and are not controlled by one single setting.

The first mental model is:

A JVM process has multiple runtime areas. The Java heap is only one of them.

The Main Runtime Areas

At a practical level, a Java developer should distinguish these areas:

AreaMain Role
Java heapStores ordinary Java objects and arrays
Java stacksStore per-thread method call frames
Program counter stateTracks where each thread is executing in JVM terms
Native method stacksSupport native calls and non-Java execution paths
MetaspaceHotSpot’s native-memory area for class metadata
Code cacheStores JIT-compiled machine code
Native memorySupports JVM internals, direct buffers, threads, libraries, and operating system resources

The JVM specification describes runtime data areas in abstract terms. HotSpot, the common OpenJDK JVM implementation, realizes some of those areas with implementation-specific structures such as metaspace and code cache.

Heap

The heap is the shared memory area where ordinary Java objects and arrays live.

When code executes:

User user = new User();

the object is allocated on the heap in the usual mental model. The local variable user holds a reference to that object, not the object body itself.

The heap is shared by Java threads. Multiple threads can refer to the same object. This is why synchronization and memory visibility matter.

Garbage collection primarily concerns the heap: the JVM finds objects reachable from roots and reclaims memory occupied by unreachable heap objects.

Java Stacks

Each Java thread has its own Java stack.

The stack stores frames for active method invocations. Each frame contains method execution state such as local variable slots, an operand stack, and a link to runtime information needed for the method.

A thread’s stack grows and shrinks as methods are called and return.

If recursion or deep call chains consume too much stack space, the JVM can throw StackOverflowError. This is different from running out of heap space.

Metaspace and Class Metadata

HotSpot stores class metadata in metaspace, which uses native memory rather than ordinary Java heap memory.

Class metadata includes runtime information derived from class files: class structures, method metadata, field metadata, constant-pool information, and related runtime representations.

Metaspace problems are usually about too many loaded classes, class loader leaks, repeated redeployment, code generation, or insufficient metaspace limits. They are not solved by assuming all memory belongs to -Xmx.

Code Cache and Native Memory

The JVM also uses memory for generated machine code. JIT-compiled methods live in the code cache.

Native memory is also used for many things outside the Java heap:

  • JVM internal data structures
  • thread stacks
  • native libraries
  • direct byte buffers
  • memory-mapped files
  • GC and compiler structures

This is why a process can consume more memory than the configured Java heap maximum.

Why -Xmx Is Not the Whole JVM

-Xmx limits the maximum Java heap size. It does not limit all memory used by the JVM process.

A JVM with -Xmx512m can still use more than 512 MB of process memory because stacks, metaspace, code cache, direct buffers, and native runtime memory are outside the Java heap.

This distinction matters when diagnosing container memory limits, operating system out-of-memory kills, direct buffer failures, or native thread creation failures.

Core Mental Model

Keep these boundaries separate:

  • Heap holds ordinary Java objects and arrays.
  • Each Java thread has its own stack of method frames.
  • Metaspace holds HotSpot class metadata outside the Java heap.
  • Code cache holds JIT-compiled machine code.
  • Native memory includes JVM internals, direct buffers, thread stacks, and operating system resources.
  • -Xmx controls heap size, not total process memory.

Final Summary

“JVM memory” is not one uniform box.

Useful JVM reasoning starts by asking which runtime area is involved: heap, stack, metaspace, code cache, direct/native memory, or thread-related state.