Java Series #0: Memory Management in Java
JVM Memory Management & Architecture

Every Java program runs inside the Java Virtual Machine (JVM) — a managed environment that handles memory allocation, execution, and cleanup automatically.
But under the hood, this is a carefully designed architecture where memory is divided into distinct runtime areas. Each area has a specific role in the lifecycle of your program.
JVM Architecture Overview
At a high level, the JVM is divided into three major subsystems:
Class Loader Subsystem – Loads classes into memory (already covered).
Runtime Data Areas (Memory) – The brain’s workspace.
Execution Engine – Executes the bytecode.
Let's zoom into the Runtime Data Areas, which is where the memory magic happens.
Runtime Data Areas
These are the five key memory regions managed by the JVM at runtime.
| Area | Scope | Description |
| 1. Method Area (MetaSpace) | Shared among all threads | Stores class-level data: method bytecode, field names, method info, constants. |
| 2. Heap | Shared among all threads | Stores all objects and arrays. Managed by the Garbage Collector. |
| 3. Java Stack | Per-thread | Each thread gets its own stack that stores method call frames, local variables, return addresses. |
| 4. PC (Program Counter) Register | Per-thread | Holds the address of the next instruction to execute. |
| 5. Native Method Stack | Per-thread | Used when Java interacts with native code (C/C++ via JNI). |
1. Method Area (MetaSpace)
Earlier called Permanent Generation (PermGen), now replaced by MetaSpace (from Java 8+).
Stores:
Class metadata (method info, fields, constructors)
Static variables
Runtime constant pool (string literals, constants)
Key Point:
This area grows dynamically in modern JVMs, depending on system memory — no more OutOfMemoryError: PermGen space.
2. Heap
The largest memory region — this is where all objects and arrays live.
Divided into:
Young Generation
Eden Space → where new objects are first created
Survivor Spaces (S0, S1) → objects that survive a GC cycle move here
Old Generation (Tenured) → long-lived objects end up here
Metaspace (technically separate, but often grouped conceptually)
Garbage Collection (GC) primarily operates here, cleaning up unused objects.
3. Stack (Java Stack)
Each thread has its own stack made up of frames, one per method call.
Each frame contains:
Local variables
Operand stack (temporary values for operations)
Return address (where to go after the method finishes)
When a method is called → a new frame is pushed onto the stack.
When it returns → the frame is popped off.
Stack memory is faster but limited, leading to
StackOverflowErrorif recursion is uncontrolled.
4. PC Register (Program Counter)
Each thread’s PC Register holds the address of the next instruction in the method being executed.
For Java methods → points to bytecode instruction.
For Native methods → undefined (JVM does not control them).
5. Native Method Stack
Used for executing native code written in C/C++ through JNI (Java Native Interface).
This allows Java to interact with system-level or hardware-level resources.
Garbage Collection (GC) – The Automatic Cleanup Crew
Java developers don’t manually free memory — the Garbage Collector (GC) automatically removes objects that are no longer reachable.
How It Works
Mark Phase:
JVM marks all live (reachable) objects from the root references (like static vars, local vars).Sweep Phase:
Unmarked (unreachable) objects are deleted.Compact Phase:
Memory is rearranged to reduce fragmentation (optional, depends on GC type).
Common Garbage Collectors
Serial GC → For single-threaded environments.
Parallel GC → Multi-threaded; improves throughput.
G1 GC (Garbage First) → Region-based, balances latency and throughput (default in Java 9+).
ZGC / Shenandoah → Ultra-low pause time for massive applications.
Visual: JVM Memory Architecture
┌──────────────────────────────────────────────┐
│ JVM │
│ │
│ ┌────────────────────────────────────────┐ │
│ │ Class Loader Subsystem │ │
│ └────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌────────────────────────────────────────┐ │
│ │ Runtime Data Areas │ │
│ │ ┌────────────────────────────────────┐ │ │
│ │ │ Method Area / MetaSpace │ │ │
│ │ │ Heap │ │ │
│ │ │ Java Stack (per thread) │ │ │
│ │ │ PC Register (per thread) │ │ │
│ │ │ Native Method Stack (per thread) │ │ │
│ │ └────────────────────────────────────┘ │ │
│ └────────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌────────────────────────────────────────┐ │
│ │ Execution Engine │ │
│ │ ┌──────────────────────────────────┐ │ │
│ │ │ Interpreter + JIT Compiler + GC │ │ │
│ │ └──────────────────────────────────┘ │ │
│ └────────────────────────────────────────┘ │
└──────────────────────────────────────────────┘
Summary
| Concept | Managed By | Purpose |
| Heap | GC | Store objects and arrays |
| Stack | Thread | Method calls and local vars |
| Method Area / MetaSpace | JVM | Class info, static vars |
| PC Register | Thread | Tracks next instruction |
| Native Stack | JNI | For native (C/C++) code |




