The Java Virtual Machine (JVM) creates a separate process for each Java application, managing memory through several key components:
- Class Loading Subsystem: Handles loading class files from file systems or networks
- Runtime Data Areas: Memory regions divided during program execution
- Execution Engine: Core component that interprets/compiles bytecode to native instructions
- Native Method Interface: Interface for Java to call non-Java code
Class Loading Mechanism
The class loading process consists of three phases:
- Loading: Locates class binary files using fully qualified names
- Linking:
- Verification: Validates class correctness
- Preparation: Allocates memory for static variables with default values
- Resolution: Converts symbolic references to direct references
- Initialization: Executes <clinit>() method for static variable initialization
Parent Delegation Model
The class loading hierarchy follows:
public class CustomLoader extends ClassLoader {
@Override
protected Class> findClass(String className) throws ClassNotFoundException {
// Custom class loading implementation
byte[] classData = loadClassData(className);
return defineClass(className, classData, 0, classData.length);
}
private byte[] loadClassData(String className) {
// Implementation to read class bytes
}
}
Runtime Data Areas
The runtime memory is divided into:
- Thread-Private:
- Virtual Machine Stack
- Program Counter
- Native Method Stack
- Thread Local Allocation Buffer (TLAB)
- Thread-Shared:
- Heap
- Metaspace (replaced Method Area in Java 8)
Virtual Machine Stack
Each thread maintains its own stack containing:
- Local Variable Table: Stores method parameters and local variables
- Operand Stack: Holds intermediate computation results
- Dynamic Linking: Resolves symbolic references during runtime
- Return Address: Tracks method exit points
Slot Mechanism
Local variables use slots for storage:
public void slotExample() {
int x = 10; // Uses 1 slot
double y = 20.5; // Uses 2 slots
Object obj = null; // Uses 1 slot (reference)
}
Escape Analysis
JVM optimizaton technique that determines object scope:
- Global Escape: Object accessible outside method/thread
- Arguement Escape: Object passed as method parameter
- No Escape: Object confined to method scope
Optimizations include:
- Lock elimination
- Stack allocation
- Scalar replacement
Metaspace (Java 8+)
Replaces the Method Area in native memory, containing:
- Class metadata (constants, methods, fields)
- Runtime constant pool
- JIT-compiled code cache