Introduction

Each Java developer knows that the JRE (Java Runtime Environment) executes bytecode. But not everyone knows that JRE is the implementation of Java Virtual Machine (JVM), a program that analyzes bytecode, interprets it, and executes it. To write code efficiently, developers need to understand the architecture of the JVM.

Throughout this article, we will learn more about the JVM architecture and its various components.

What is JVM in Java?

An implementation of a physical machine in software is called a virtual machine. As Java runs on a virtual machine, it is built using the concept of WORA (Write Once Run Anywhere).

The built-in Java compiler compiles the Java file into a Java .class file, then that .class file is passed to the JVM, so the class can get loaded and executed. The architecture of the JVM is illustrated below.

It is:

  • A specification that describes how Java Virtual Machines work. However, implementation providers are free to choose which algorithm to implement. Its implementation comes from Oracle and other companies.
  • This implementation is known as JRE (Java Runtime Environment).
  • Runtime Instance When you run a java class from the command prompt, a JVM instance gets created.

Class Loader Subsystem

In RAM, the JVM is located. The ClassLoader subsystem loads class files into RAM during execution. Its Java feature called dynamic class loading allows classes to be loaded dynamically. A class file (.class) is loaded, linked, and initialized for the first time when a reference is made to a class (not at compile time).

1) Loading

A ClassLoader is responsible for loading compiled classes into memory (.class files). In general, class loading begins with loading the main class (the one with a static main() method declaration). Class loading is carried out based on the class references in the already-running classes as follows:

  • When bytecode makes a static reference to a class (e.g., System.out)
  • When bytecode create a class object (e.g. Person person = new Person("John"))

2) Linking

The Linking process consists of verifying and preparing a loaded class or interface, its direct superclasses and superinterfaces, and its element type based on the properties listed below.

  • The class or interface must fully load before it can be linked.
  • Verifying and preparing a class or interface is required before initializing it (the next step).
  • During the linking process, JVM throws an error when the program takes some action requiring linkage to the class or interface involved in the error.

3) Initialization

It is the step where JVM performs initialization logic for each loaded class or interface(e.g., calling the class constructor). The JVM is multi-threaded, so a class or interface initialization must be carefully handled and correctly synchronized to prevent another thread from attempting the same class or interface(i.e., making it thread-safe).

Class loading ends with assigning the static variables with their original values in the code, followed by the execution of the static blocks (if any). The code execution is performed in a class hierarchy from top to bottom and from parent to child.

Code Sample

Here is an example of printing the classloader name :

public class ClassLoaderExample 

    public static void main(String[] args) 
    { 
        // Let's print the current class's classloader name.  
        //Application/System classloader will perform loading of this class 
        Class c=ClassLoaderExample.class; 
        System.out.println(c.getClassLoader()); 
        //If we try to print the classloader name in String format, the outpot will be null because it is an in-built class is located in rt.jar and Bootstrap classloader loads it 
        System.out.println(String.class.getClassLoader()); 
    } 
}


Output

sun.misc.Launcher$AppClassLoader@4e0e2f2a

null

write your code here: Coding Playground

Hope this article gave you a better understanding of JVM Architecture in Java.