2451. Java Advanced - Java Virtual Machine

Java Virtual Machine

1. Java Virtual Machine

1.1 What is a JVM in Java?

A Virtual Machine is a Software implementation of a Physical Machine, Java was developed with the concept of WORA (Write Once Run Anywhere) which runs on a VM. The compiler will be compiling the java file into a java .class file. The .class file is input to JVM which Loads and executes the class file.

1.2 JVM Specification and Implementation

JVM can have different implementations, as long as they adhere to the specs. The JVM specs(Java 7) can be found at https://docs.oracle.com/javase/specs/jvms/se7/html/. Oracle has its own JVM implementation (called HotSpot JVM), whereas IBM has its own (called J9 JVM).

1.3 Architecture of JVM

image As shown in the above architecture diagram JVM is divided into three main subsystems:

  • Class Loader Subsystem
  • Runtime Data Area
  • Execution Engine

2. Class Loader Subsystem

Java’s dynamic class loading functionality is handled by the class loader subsystem. It loads, links and initializes the class when it refers to a class for the first time at runtime, not at compile-time. It performs three major functionality such as Loading, Linking, and Initialization.

2.1 Loading

Classes will be loaded by this component. BootStrap Class Loader, Extension Class Loader, Application Class Loader are the three class loaders which will help in achieving it. The Class Loaders follow Delegation Hierarchy Algorithm while loading the class files. image

  • BootStrap Class Loader – Responsible for loading classes from the bootstrap class path at jre/lib/rt.jar of the root directory of JDK.
  • Extension Class Loader – It is the child class of Bootstrap Class Loader. Responsible for loading classes which are inside jre/lib/ext folder.
  • Application Class Loader – It is the child class of Extension Class Loader. Responsible for loading Application Level Classes. The path of these classes is defined by CLASSPATH environment variable.

PS: ClassNotFoundException comes when JVM tries to the load a class at runtime dynamically.

2.2 Linking

The JVM basically uses the symbol table stored in the run-time constant pool for the linking process.

  • Verify – Bytecode verifier will verify whether the generated bytecode is proper or not if verification fails we will get verification error.
  • Prepare – For all static variables memory will be allocated and assigned with default values.
  • Resolve – All symbolic memory references are replaced with the original references. To accomplish this, the symbol table in the run-time constant memory of the method area of the class is used.

PS: NoClassDefFoundError comes at resolve phase when problematic class was present during compile time but not available during runtime for any reason.

2.3 Initialization

This is the final phase of Class Loading, here all static variable will be assigned with the original values and static block will be executed.

3. Runtime Data Area

The JVM spec defines certain run-time data areas that are needed during the execution of the program. Some of them are created while the JVM starts up. Others are local to threads and are created only when a thread is created (and destroyed when the thread is destroyed). Runtime Data Area is divided into 5 major components:

  • Method Area – All the Class level data will be stored here including static variables. Method Area is one per JVM and it is a shared resource.
  • Heap Area – All the Objects and its corresponding instance variables and arrays will be stored here. Heap Area is also one per JVM since Method area and Heap area shares memory for multiple threads the data stored is not thread safe.
  • Stack Area – For every thread, a separate runtime stack will be created. For every method call, one entry will be made in the stack memory which is called as Stack Frame. All local variables will be created in the stack memory. Stack area is thread safe since it is not a shared resource. Stack Frame is divided into three sub-entities such as:
    • Local Variable Array – Related to the method how many local variables are involved and the corresponding values will be stored here.
    • Operand stack – If any intermediate operation is required to perform, operand stack acts as runtime workspace to perform the operation.
    • Frame data – All symbols corresponding to the method is stored here. In the case of any exception, the catch block information will be maintained in the frame data.
  • PC(Program Counter) Registers – Each thread will have separate PC Registers, to hold address of current executing instruction once the instruction is executed the PC register will be updated with the next instruction.
  • Native Method stacks – Native Method Stack holds native method information. For every thread, separate native method stack will be created.

4. Execution Engine

The bytecode which is assigned to the Runtime Data Area will be executed by the Execution Engine. The Execution Engine reads the byte code and executes one by one.

  • Interpreter – Reads the bytecode, interprets it and executes it one by one. The interpreter interprets the bytecode faster but executes slowly. The disadvantage of the interpreter is that when one method called multiple times, every time interpretation is required.
  • JIT Compiler – JIT Compiler neutralizes the disadvantage of the Interpreter ( a single method called multiple times, each time interpretation is required ), The Execution Engine will be using the help of Interpreter in converting but when it found repeated code it uses JIT compiler which compiles the entire bytecode and changes it to native code. This native code will be used directly for repeated method calls which improve the performance of the system.
    • Intermediate Code generator – produces intermediate code
    • Code Optimizer – Code Optimizer is responsible for optimizing the intermediate code generated above
    • Target Code Generator – Target Code Generator is responsible for Generating Machine Code/ Native Code
    • Profiler – Profiler is a special component, it is responsible for finding the hotspots (i.e) Used to identify whether the method is called multiple time or not.
  • Garbage Collector - Garbage Collector is a part of Execution Engine, it collects/removes the unreferenced objects. Garbage Collection can be triggered by calling System.gc(), but the execution is not guaranteed. Garbage collector of JVM collects only those objects that are created by new keyword. So if you have created any object without new, you can use finalize method to perform cleanup.

Java Native Interface (JNI): JNI interacts with the Native Method Libraries and provides the native libraries(c,c++) required for the Execution Engine. Native Method Libraries: It is a collection of the Native Libraries(c,c++) which is required for the Execution Engine.

5. References