Mon May 07 2018
What is JVM? How does it work?
Whether you are a newbie or experienced, if you use Java then you might know that Java bytecode is executed in Java Runtime Environment, and the most important element of the JRE is Java Virtual Machine (JVM) which analyzes and executes Java bytecode. So, learn and understanding the architecture of JVM could help you to gain knowledge on the overall insight of a virtual machine. Going through this article you’ll get more knowledge about Java Virtual Machine. Then you will be able to understand what actually happens when you run a Java program. So, let’s dive into deep.
What is Java Virtual Machine?
Previously, you have learned that in high-level languages like C and C++ the source code is directly converted to the computer understandable binary code by a compiler after execution. In Java, this process is quite similar but not perform the same. when a Java program is compiled, it generates the bytecode which can be run on any computer that has JRE installed on it. This compiled file goes into various steps when we run it. These steps together describe as the whole JVM. So, JVM is a part of JRE. The role of the JVM is to read the Java application through the Class Loader and execute it along with the Java API. You know that Java was designed to run based on WORA that means Write Once Run Anywhere. But this was missed most of the time. So, without changing the execution code, JVM runs on all kinds of hardware to execute the Java Bytecode.
There have three notions of JVM. Those are -
-
A specification - where working of Java Virtual Machine is specified. But implementation provider is independent to choose the algorithm. Its implementation has been provided by Sun and other companies.
-
An implementation - Its implementation is known as JRE (Java Runtime Environment).
-
Runtime Instance - Whenever you write java command on the command prompt to run the java class, an instance of JVM is created.
Let’s see the architecture of JVM.
Class Loader
The JVM has a flexible Class Loader architecture that allows a Java application to load classes in custom ways and each and every class is loaded by some instance of a java.lang.ClassLoader. If a Java class is invoked and needs to be executed on a JVM, a special Java component called a classloader is used to find the Java class of interest. Compile that file into bytecode and execute the bytecode of that class file on the JVM. Class Loader follows the steps, these are -
-
Load - A class is obtained from a file and loaded to the JVM memory.
-
Verification - Bytecode verifier will verify whether the generated bytecode is proper or not if verification fails we will get a verification error. This is the most complicated test of the class to load processes, and it takes the longest time.
-
Preparation - Prepare a data structure that assigns the memory required by classes and indicates the fields, methods, and interfaces defined in the class.
-
Resolve - All symbolic memory references are replaced with the original references from Method Area.
-
Initialize - Initialize the class variables to proper values. Execute the static initializers and initialize the static fields to the configured values.
The three default class loader are used in Java.
-
Bootstrap - Every JVM implementation must have a bootstrap class loader, capable of loading trusted classes. It loads core Java API classes present in JAVA_HOME/jre/lib directory. This path is popularly known as bootstrap path. It is implemented in native languages like C, C++.
-
Extension - It is child of bootstrap class loader. It loads the classes present in the extensions directories JAVA_HOME/jre/lib/ext(Extension path) or any other directory specified by the java.ext.dirs system property. It is implemented in Java by the sun.misc.Launcher$ExtClassLoader class.
-
System or Application - It is child of extension class loader. It is responsible to load classes from application class path. It internally uses Environment Variable which mapped to java.class.path. It is also implemented in Java by the sun.misc.Launcher$AppClassLoader class.
Runtime Data Areas
Runtime Data Areas are the memory areas assigned when the JVM program runs on the OS. The runtime data areas can be divided into several areas. These are -
-
Method Area - In method area, all class level information like class name, immediate parent class name, methods and variables information etc. are stored, including static variables. There is only one method area per JVM, and it is a shared resource.
-
Heap Area - Heap is a memory place where the objects and its instance variable are stored. Each time an object is created in Java it goes into the area of memory known as heap.
-
Stack Area - For every thread, JVM creates one run-time stack which is stored here. Every block of this stack is called activation record/stack frame which stores methods calls. All local variables of that method are stored in their corresponding frame. After a thread terminates, it’s run-time stack will be destroyed by JVM. It is not a shared resource.
-
PC Register - PC Register basically is an address of current instruction is being executed. It exists for one thread and is created when the thread starts.
-
Native Method Stack - Native methods are those which are written in languages other than Java. It stores native method information.
Execution Engine
This is the core of the JVM. Execution engine can communicate with various memory areas of JVM. Each thread of a running Java application is a distinct instance of the virtual machine's execution engine. The byte code is assigned to the runtime data areas in the JVM via class loader is executed by the execution engine. It reads the byte-code line by line, uses data and information present in various memory area and executes instructions. It can be classified in these three parts -
-
Interpreter - It interprets the bytecode line by line and then executes. As it interprets and executes instructions one by one, it can quickly interpret one bytecode, but slowly executes the interpreted result.
-
Just-In-Time (JIT) Compiler - It is used to increase efficiency of interpreter. It compiles the entire bytecode and changes it to native code so whenever interpreter sees repeated method calls, JIT provide direct native code for that part so re-interpretation is not required, thus efficiency is improved.
-
Garbage Collector - Garbage collection is the process that aims to free up occupied memory that is no longer referenced by any reachable Java object, and is an essential part of the JVM's dynamic memory management system. It tracked live objects and everything else designated garbage.
Native Interface
It is an interface which interacts with the Native Method Libraries and provides the native libraries(C, C++) required for the execution. It enables JVM to call C/C++ libraries and to be called by C/C++ libraries which may be specific to hardware.
Native Method Libraries
Native Libraries is a collection of the Native Libraries(C, C++) which are needed by the Execution Engine.
Now, take a look how it works
-
When your Java project builds, it translates the source code (contained in *.java source files) to Java bytecode (most often contained in *.class files). This takes your high-level code one step closer to machine code, but not quite there yet.
-
This bytecode is a collection of compact instructions; easier for a machine to interpret, but less readable.
-
The JVM takes your compiled platform-neutral byte code and interprets it to run platform-specific machine code. It can also compile it into native code with a JIT. Thus, it is in the JVM where your code results.
-
Therefore, in the JVM, your platform-neutral threading code gets turned into platform-specific threading code.
-
When you create an Object, Java allocates memory for both objects and primitives. Java determines when these items are no longer referenced, and, therefore, can have their memories reclaimed.
-
Essentially pass this Java bytecode to the Java Virtual Machine.
-
The interpreter in the Java Virtual Machine usually starts compiling the entire bytecode at runtime, following the principles of so-called just-in-time compilation.
-
This makes for the typical, albeit often slight delay when opening a Java application, but generally enhances the program performance compared to interpreted compilation.
Speed and its platform-specific features can be considered as the disadvantages of JVM. As a program needs to be translated from source code to byte code and then from byte code to executable code, the speed of execution of a program is decreased when compared to other high-level languages. JVM should be without errors as a Java program depends on JVM. So, any failure of JVM leads to the failure of the program. Hope you like this article. You can share your comments in comment section. Thank you!