JVM Memory Model
The Java Virtual Machine (JVM) divides its managed memory into distinct runtime data areas during program execution:
- Shared across threads: Heap, Method Area
- Thread-local: Program Counter Register, JVM Stack, Native Method Stack
Program Counter Register
A small memory space that acts as a pointer to the current bytecode instruction being executed by a thread. It ensures correct resumption after thread context switches and is the only JVM region immune to OutOfMemoryError.
JVM Stack
Private to each thread and created alongside it. Each method invocation creates a stack frame containing:
- Local variable table (holds primitives and object references)
- Operand stack
- Dynamic linking info
- Method return address
Two exceptions may occur:
StackOverflowError: when call depth exceeds allowed limitOutOfMemoryError: if native memory allocation fails during stack creation (though HotSpot doesn't support dynamic expansion)
Native Method Stack
Similar to JVM stack but serves native methods (JNI). Throws same exceptions under analogous conditions.
Heap
Largest JVM memory area, shared among all threads. Primary responsibilities:
- Stores object instances and arrays
- Managed by garbage collector
- Uses Thread Local Allocation Buffers (TLABs) to reduce synchronization overhead during object allocation
Method Area
Shared region storing:
- Class metadata
- Runtime constant pool
- Static variables
- JIT-compiled code cache
Runtime Constant Pool
Part of method area holding compile-time constants and symbolic references from .class files. Populated during class loading.
Object Lifecycle
Object Creation
- Verify class reference in constant pool and ensure class is loaded/initialized
- Allocate memory in heap
Memory Allocation Strategies
- Pointer Bumping: Used with compacting GCs where heap is contiguous (used/free regions separated by a pointer)
- Free List: Maintains list of available memory chunks for non-contiguous heaps
Allocation strategy depends on GC's compaction capability.
Object Memory Layout
Object Header
Contains:
- Runtime metadata (hash code, GC age, lock info)
- Class pointer (type metadata reference)
- Array length (for array objects)
Instance Data
Actual field values defined in class hierarchy (including inherited fields).
Padding
Ensures object size is multiple of 8 bytes (HotSpot requirement). Added only if instance data isn't already aligned.
Object Access
Two primary access mechanisms:
- Handle-based: Reference points to handle containing object/class pointers. Simplifies GC relocation but adds indirection overhead
- Direct pointer: Reference points directly to object. Faster access but requires updating all references during GC relocation
HotSpot uses direct pointers for performance.
Garbage Collection
Identifying Garbage
Reference Counting
Tracks reference counts per object. Fails with circular references.
Reachability Analysis
Uses GC Roots as starting points:
- Local variables in active stack frames
- Static fields
- JNI references
- System classes and interned strings
- Locked monitors
Objects unreachable from GC Roots are considered garbage. HotSpot uses this approach.
Reference Types (JDK 1.2+)
| Type | Behavior |
|---|---|
| Strong | Never collected while referenced (Object obj = new Object()) |
| Soft | Collected only when memory is critically low (SoftReference) |
| Weak | Collected at next GC cycle (WeakReference) |
| Phantom | Only for cleanup notifications (PhantomReference) |
Method Area GC
Collects:
- Unused constants (e.g., unreferenced string literals)
- Unloaded classes (requires: no instances, classloader collected, no Class object references)
Class unloading is optional and implementation-dependent.
GC Algorithms
Generational Hypotheses
- Weak: Most objects die young
- Strong: Older objects tend to survive longer
- Intergenerational: Cross-generational references imply similar lifetimes
Heap Organization
- Young Generation: Eden + Survivor spaces (typically 8:1:1 ratio)
- Old Generation: Long-lived objects
Collection Types
- Minor GC: Young generation collection
- Major GC: Old generation collection (CMS-specific)
- Mixed GC: Young + partial old generation (G1-specific)
- Full GC: Entire heap + method area
Core Algorithms
- Mark-Sweep: Identify live objects then reclaim dead ones (causes fragmentation)
- Copying: Move live objects between survivor spaces (Eden → Survivor → Old)
- Mark-Compact: Relocate live objects to one end before sweeping (eliminates fragmentation)
Stop-The-World: Application pauses during object relocation phases.
Popular Collectors
CMS (Concurrent Mark Sweep)
- Concurrent phases reduce pause times
- Drawbacks: Fragmentation, floating garbage, CPU intensive
G1 (Garbage-First)
- Region-based heap layout
- Predictable pause times
- Mixed collections include both young and old regions
Allocation Policies
- Eden First: Default allocation location
- Large Objects: Directly allocated in old generation (
-XX:PretenureSizeThreshold) - Age-Based Promotion: Objects surviving multiple Minor GCs move to old generation (default threshold: 15)
- Dynamic Tenuring: Promote objects earlier if same-age objects exceed 50% of survivor space
- Promotion Guarantee: Before Minor GC, verify old generation can accommodate worst-case promotion scenario
Clas Loading
Loading Triggers
Initialization occurs when:
- Instantiating objects (
new) - Accessing static fields/methods (except compile-time constants)
- Reflection usage
- Initializing subclasses
- JVM startup (main class)
- Dynamic language features (MethodHandle)
- Interface default methods initialization
Loading Process
1. Loading
- Obtain bytecode via fully qualified name
- Convert to runtime data structures
- Create
java.lang.Classinstance
2. Verification
Ensures bytecode validity through:
- File format checks
- Metadata validation
- Bytecode verification
- Symbolic reference resolution
3. Preparation
Allocate memory for static fields and initialize to type defaults (except static final constants initialized here).
4. Resolution
Convert symbolic references (logical names) to direct references (memory addresses).
5. Initialization
Execute <clinit>() method containing:
- Static field assignments
- Static initializer blocks
Key characteristics:
- Parent
<clinit>()runs before child - Thread-safe (only one thread executes per class)
- Not generated if no static initializers exist
Class Loaders
Hierarchy
- Bootstrap ClassLoader: Loads core Java libraries (
rt.jar). Implemented in native code. - Extension ClassLoader: Loads
$JAVA_HOME/lib/extor paths injava.ext.dirs - Application ClassLoader: Loads classpath entries. Default system loader.
Delegation Model
Each loader delegates to parent before attempting local loading. Ensures:
- Core classes always loaded by bootstrap loader
- Prevents duplicate class definitions
- Maintains security boundaries
Class identity includes both binary name AND loading classloader. Two classes with same name loaded by different loaders are considered distinct.