JVM (Java Virtual Machine) Architecture
We already know that byte code will be executed by JRE (Java Runtime Environment), but actually, JRE is the implementation of JVM (Java Virtual Machine), and then it analyzes the bytecode, interprets the code, and executes it.
What is the (Java Virtual Machine) JVM?
When the compiler compiles the Java file into a .class file, that .class file works as input into the JVM, which Loads and executes the class file. The virtual machine is a software implementation of a physical machine. when we try to execute our .class file, JVM comes in picture. It takes the .class file and loads all the dependent libraries to provide a smooth execution environment. Loot at the JVM architecture to understand it in detail.
JVM Architecture Diagram
JVM is divided into three subsystems:
A. ClassLoader Subsystem
Java has a dynamic class loading functionality which is handled by the class loader subsystem. It loads the class, links the classes and packages and initializes the class file at runtime.
Classes are been loaded by this component. There are mainly three class loaders which will help in achieving it.
- Bootstrap Class Loader – It is responsible for loading classes from the bootstrap classpath, nothing but rt.jar. This class loader has the highest priority.
- Extension ClassLoader – It is responsible for loading classes that are inside the ext folder (jre\lib).
- Application ClassLoader – It is responsible for loading Application Level classpath.
Linking between classes are done by this component, it works in below phases-
- Verify – Here bytecode verifier verifies the generated bytecode that is proper or not if not it throws verification error.
- Prepare – Here memory will be allocated and assigned with default values to all the static variables.
This is the last phase of Class Loading, here original values will be assigned to all static variables, and the static block will be executed.
B. Runtime Data Area
It is divided into five major components-
- Method Area – Method Area stores all the class level data, including static variables. There is one method area per JVM.
- Heap Area – All the Objects, their corresponding instance variables and arrays stores in Heap memory. There is only one Heap Area per JVM.
- Stack Area – A separate runtime stack will be created for every thread. One entry will be made in the stack memory for every method call which is called Stack Frame. All the local variables are created in the stack memory. The stack area is thread-safe since it does not share the resources.
- PC Registers – PC Registers are used to hold the address of current execution thread instruction. Every thread has its separate PC Register. Once the execution is done PC Register unhold the thread and ready to hold the next instruction.
- Native Method stacks – This Stack holds native method information. For every thread, a separate native method stack will be created.
C. Execution Engine
Execution Engine executes the bytecode which is assigned to the Runtime Data Area. The Execution Engine reads the bytecode and executes one by one.
- Interpreter – Interpreter interprets the bytecode faster, but it takes time to execute it. The main disadvantage of the Interpreter is that every time a new interpretation is required when a method called multiple times.
- JIT Compiler – The Just-in-Time (JIT) Compiler is a component of JRE which is used to improve the performance of Java application at run time. It reduces the execution time taken by the Interpreter. The main advantage of Java is "Write once and run anywhere" is byte code. How the byte code will be converted into native code instruction makes a huge impact on the speed of the system. These byte codes can be compiled to native code, can be interpreted or directly executed on a processor whose Instruction Set Architecture is the byte code specification. As we learn Interpreter makes application slow. The execution engine takes the help of the Interpreter to convert into byte code but when it finds repeated code it uses the JIT Compiler which compiles the entire byte code and changes it into the native code. Native code can be used directly for repeated method calls which improve the performance of the System.
- Garbage Collector - In C++ we have used Destructor to free up the memory occupied by the object. In Java we don't need to take care of it, Garbage Collector does it for us. Garbage Collector always runs in the background and destroys the unreachable or unuseful object.
The Process of Garbage Collection is Automatic in Java.