The Java Virtual Machine (JVM) executes Java bytecode through several key steps, transforming high-level Java code into machine-executable instructions. Here’s an overview of the execution process:
1. Class Loading
- The JVM starts by loading
.class
files, which contain Java bytecode (compiled Java code). - The ClassLoader subsystem loads these classes into memory dynamically when they are needed.
2. Bytecode Verification
- The JVM’s Bytecode Verifier checks for security and correctness:
- Ensures there are no memory access violations.
- Checks for proper use of data types.
- Prevents stack overflow or underflow errors.
- This prevents the execution of malicious or corrupted code.
3. Execution Engine
- The execution engine is responsible for executing the bytecode. It does this in two main ways:
a) Interpretation
- The JVM starts by interpreting bytecode line-by-line.
- This method is slower because each instruction requires an extra level of translation before execution.
b) Just-In-Time (JIT) Compilation
- To improve performance, the JVM uses JIT compilation, which converts frequently executed bytecode into native machine code for direct execution.
- The JIT compiler compiles sections of bytecode into native instructions on the fly, reducing the need for repeated interpretation.
4. Garbage Collection
- JVM automatically manages memory through Garbage Collection (GC).
- It identifies and removes objects that are no longer needed, freeing up memory.
5. Runtime Optimizations
- The JVM continuously monitors execution to optimize performance:
- HotSpot Optimization: Identifies frequently used code (hot spots) and optimizes it further.
- Inline Caching: Speeds up method calls by caching method lookup results.
- Escape Analysis: Determines if an object can be allocated on the stack instead of the heap to improve performance.
6. Native Code Execution
- After the bytecode is compiled by the JIT, it is executed as native code on the host machine’s processor.
- The JVM interacts with the Operating System (OS) and Native Libraries via the Java Native Interface (JNI).
Summary
The JVM executes Java bytecode by:
- Loading classes dynamically.
- Verifying bytecode for security.
- Interpreting or compiling bytecode into native code (via JIT).
- Managing memory through garbage collection.
- Optimizing execution with various runtime techniques.