In this tutorial, we will unfold two of the most important questions of the Java programming environment i.e What is JVM (Java Virtual Machine)? and What is JIT?. In an abstract, these two components work together to execute a Java program more efficiently and with higher speed.
What is JVM (Java Virtual Machine)
JVM is virtually just a machine on which the Java programs actually run and operate. A Java program cannot run on any machine that doesn’t have or doesn’t support JVM. It is a core part of the Java Runtime Environment (JRE). The JVM is loaded with many specifications that work cooperatively to run a Java program. It is platform-dependent by nature i.e for each type of operating system there is a different JVM.
A developer need not worry about installing and configuring JVM. It comes built-in with the JDK package.
The platform-independent feature of Java is made possible by JVM. The JVM is the one that can convert the Java bytecode into a machine-understandable code. The conversion of Java Bytecode to machine code takes place in multiple specifications inside a JVM.
Specifications of JVM
The Class Loader is a subpart of JVM. It mainly reads the .class file that is generated using the javac command, extracts some core information from that file, and stores that information in the Method Area. The Class Loader can get information like classes and their names, variables, methods, interfaces, etc.
A method area is like a store where all the class level information like class names, variable names, method names, enums, etc. are stored. It is a unique area in JVM which is shared among other classes.
We know Java is an object-oriented programming language where everything is in the form of objects. These objects are real entities that need memory to work. The Heap in JVM stores all the data & information about objects that are created during the lifetime of execution of a Java program. Just like the Method area, there is only one Heap Area which is a shared resource in JVM.
Program Counter Registers (PC Registers) address storing registers in JVM. These registers store the address of the current instruction that is being executed. Java is a multi-threaded programming language which means there can be multiple threads running at the same time. Java provides multiple PC Registers to store the address of each thread that is being executed.
The Execution Engine is the one that actually executes the Java bytecode (.class files) inside JVM. The execution engine reads the contents of the .class files line by line and extracts information that is then converted to machine code (which is understandable by the computer). The Execution Engine has three other subparts that work together to complete a program’s execution.
- Interpreter: The Interpreter is a part of the execution engine that reads the Java generated bytecode sequentially one line at a time.
- Just In Time (JIT) Compiler: The JIT compiler is mainly used to improve most of the efficiency of a program’s execution. It converts a similar kind of bytecode to machine code at a time. Whenever the interpreter gets another repeated bytecode, the JIT compiler provides the compiled machine code at that instance of time.
- Garbage Collector: Each object created by Java during program execution consumes memory. These objects are later not referenced by the program and therefore are of no use. These unreferenced objects are removed from the memory by the Garbage Collector to manage memory. This increases memory efficiency.
Native Method Stack
A Native Method Stack is used to store information about the native methods that are used in a Java application. There is just one Native Method Stack for one execution thread. Multiple Native Method Stacks are used for multiple execution threads.
Native Method Interface
It is an interface between the JVM and other native libraries like C/C++. Whenever there is a need for external native libraries in JVM this interface is used. This interface can call native libraries or be called by native libraries.
Just In Time (JIT) compiler
Java programs are really fast in execution. This speed is mainly achieved by the ultimate efficiency and performance of Java Virtual Machine. The architecture of JVM has a few other components that also contribute to its performance. One of the main components on which a program’s execution relies is known as the Just In Time Compiler (JIT).
The JIT compiler interacts with the JVM at runtime and compiles similar bytecodes into native machine code. This machine code is easily understood by the host machine and can be executed really fast. Whenever there is a repetition of the same code that is being executed, the JIT compiler provides its native machine code at that instance so that the repeated code doesn’t take the same amount of process time again. This saves execution time and increases efficiency.
The JIT compiler achieves much higher execution efficiency only when there is a repetition of the same bytecode. JIT compiles similar bytecodes together and converts them to native machine code. JIT will not be much performance efficient when the repeated code is not frequent.
Oracle uses the Hotspot Compiler to increase the efficiency of program execution. Hotspot compiler identifies and prioritizes Java code so that code with higher priority gets compiled before low priority code.