The Java Virtual Machine is a critical component of the java ecosystem, enabling java’s “write once and run anywhere” promise. It’s an abstract computing machine that provides a runtime environment to run java’s bytecode.
- The JVM is a virtual machine that is responsible for running java’s bytecode generated by the java compiler (
javac
). - It acts as an intermediary between the bytecode and the underlying hardware and platform specific implementation.
- The JVM is offered for most operating systems thus being able to transcode bytecode to system level operations to run the program. Due to this same written java code can be run on any operating system without recompiling as the hard work is done by the JVM.
Working of JVM
- Compilation - The java compiler(
javac
) converts the.java
source code into.class
files containing the platform independent bytecode. - Execution - The JVM loads the bytecode, interprets or compiles it to native machine code, executing it on host’s system.
- Abstraction - The JVM handles system-specific tasks. eg. memory management, hardware interactions.
JVM architecture
The JVM consists of several components that work together to execute Java programs. These are divided into three main subsystems:
Class Loader Subsystem
- loads, links and initialized the
.class
files into the jvm for execution. - process:
- loading:
- reads the
.class
file from the file system or network and creates a binary representation in memory. - loads the core java libraries and the class for further linking.
- reads the
- linking:
- Ensures the bytecode is valid and adheres to java’s rules.
- Allocates memory for static variable and assign default values.
- Resolves symbolic references to direct references in memory.
- Initialization
- Executes the static initializers and assign initial value to static vars.
- loading:
Runtime Data Areas (Memory Areas)
- Stores data required during program execution. These areas are shared or thread-specific.
- Components -
- Method Area
- Stores class-level data, such as the runtime constant pool, field/method data, and bytecode of methods.
- Shared across all threads
- Heap
- Stores all object instances and arrays dynamically allocated during runtime.
- Shared across all threads.
- Garbage collector is responsible for cleaning the heap memory.
- Stack
- Stores local variables, method call frames, and intermediate computation results for each thread.
- Private to each thread.
- Each method call creates a stack frame that contains the data related to that method call such as local vars, reference to runtime constant pool, etc.
- Register
- Holds the address of the currently executing JVM instruction for each thread.
- Private to each thread.
- Native Method Stack
- Supports execution of native methods (written in C/C++ and called via JNI - Java Native Interface).
- Private to each thread
- used when Java calls a system-specific function (e.g., file I/O in the OS).
- Method Area
Execution engine
- Executes the bytecode by interpreting it or compiling it to native code
- Language can be interpreted or JIT compiled depending upon the implementation.
- Garbage collector automatically manages heap memory by reclaiming space from objects no longer being referred.
- Allows java to call native libraries in C/C++.