Runtime memory areas in Java
Heap, stacks, metaspace, PC register, native method stack.
The shared rooms
Some memory belongs to the whole JVM and all threads share it: the heap (every object and array), metaspace (class metadata, stored in native memory outside the heap) and the code cache (machine code produced by the JIT).
Each thread's private desk
Every thread also gets its own private areas: a JVM stack with one frame per method call (holding locals and partial results), a PC register (the address of the instruction it's running) and a native method stack for native code.
Dive until it breaks
What does this print?
int calls = 0;
void down() { calls++; down(); }
void main() {
try {
down();
} catch (StackOverflowError e) {
boolean deep = calls > 100;
System.out.println("caught: " + deep);
}
}caught: trueThrows OutOfMemoryErrorcaught: false
Show the answer
Each call to down() pushes a new frame onto this thread's stack until it's full, which throws StackOverflowError. By then far more than 100 frames were pushed. Deep recursion fills the stack, not the heap.
Goodbye PermGen
Up to Java 7, class metadata lived in PermGen, a fixed-size part of the heap tuned with -XX:MaxPermSize. Java 8 removed PermGen and replaced it with metaspace in native memory. It grows as needed; cap it with -XX:MaxMetaspaceSize.
An old runbook
-XX:MaxPermSize=256mPermGen no longer exists. Recent JDKs don't even start with this flag (Unrecognized VM option).
-XX:MaxMetaspaceSize=256mCaps metaspace, where class metadata lives since Java 8.
Free thread safety
Why can two threads run the same method at once without their local variables getting mixed up?
Think about it, then reveal the answer
Locals live in each thread's own stack frame, which no other thread can see. Only objects on the shared heap can be reached by several threads.
Pick the right knob
On call, the error names the area, and the area names the fix: StackOverflowError means one thread's stack (-Xss, or less recursion). OutOfMemoryError: Java heap space points at objects (-Xmx, or a leak). OutOfMemoryError: Metaspace points at classes (-XX:MaxMetaspaceSize, or a class loader leak).
Key takeaways
- Shared: heap, metaspace, code cache
- Per thread: JVM stack, PC register, native method stack
- Deep recursion fills the stack: StackOverflowError
- Metaspace is native memory, outside the Java heap
The JVM spec says that while a thread runs a native method, the value of its PC register is undefined. It only tracks bytecode positions.
Practice questions
What does this print?
int depth = 0;
void dive() { depth++; dive(); }
void main() {
try {
dive();
} catch (StackOverflowError e) {
System.out.println("stack full");
}
System.out.println(depth > 1000);
}- stack full true
- Throws OutOfMemoryError
- stack full false
- true
Check your answer
stack full true. Every call to dive() pushes a frame on the thread's stack until it overflows. The StackOverflowError is caught, and by then thousands of frames had been pushed.
An old Java 7 runbook says to tune -XX:MaxPermSize. In modern Java, where does class metadata live?
- In metaspace, in native memory outside the heap
- In each thread's stack
- In PermGen, which is now unlimited
- In the young generation
Check your answer
In metaspace, in native memory outside the heap. PermGen was removed in Java 8 and replaced by metaspace. It grows in native memory and can be capped with -XX:MaxMetaspaceSize.