How the Java Virtual Machine Works

September 30, 2021

Java Virtual Machine (or JVM) allows a computer to interpret or run Java programs. It acts as a compiler for generating machine code. All Java programs require a Runtime Environment.

If you want Java apps to run at all, you’ll need a JVM (Java Virtual Machine). Java code’s main method is invoked by the JVM and JVM is part of the JRE (Java Runtime Environment).

There is a Java application slang phrase called WORA (Write Once Run Anywhere). As a result, Java code produced on one system can run on any other Java-enabled system without any changes.


Java Virtual Machine (JVM) allows for all of this to happen. Class files with the same names are generated by the Java compiler as part of the compilation process for a .java file.

This ‘.class’ file performs a sequence of tasks when executed. The steps below describe the JVM as a whole, and we will discuss them further in this article.

Types of virtual machines

  • System-based virtual machines (SVM): As a replacement for physical computers, SVMs were developed. A host computer runs them and uses their hardware resources.
  • Application-based virtual machines (AVM): The host machine allows a single process to execute as an application without involving any hardware whatsoever. Process-based virtual machines are another name for them. JVMs belong to this group of VMs, which we will discuss at length in this article.
  • Application-level virtual machine (AVM): Allows a single process to execute as an application on the host machine without any hardware components. Thus, they are also known as process-based virtual machines.

This .class file breaks down the JVM into numerous phases that describe how it works:

  • ClassLoader
  • JVM Memory
  • Execution Engine
  • Java Native Interface (JNI)
  • Native Method Libraries We will now discuss all of these phases below starting from the first one.

Class loader subsystem

There are three components of the class loaders:

  1. Application class loader
  2. Extension class loader
  3. Bootstrap class loader

As one of the phases of JVM, class loader mainly consists of the activities listed below:

  • Loading: The ClassLoader loads ‘.class’ files into the method area and creates the binary data for the class file. For JVM, the method region of each .class file contains the following information that is critical.
  • Classes are named after their superclass or root class.
  • .class files can be classified as Class or Interface.
  • There is a lot of detail on the modifier, variables, and method.

For each .class file loaded, JVM produces a Class object to represent it in heap memory. One should note that this class object generated belongs to the Java.lang package’s.

If the programmer wants information about a class such as its name, its parent, or any methods/variables associated with it, they can use these Class objects. The getClass() function of the Object class can be used specifically to retrieve theses object references. The class object built by JVM to represent the .class file in memory is demonstrated in this Java application below.

import java.lang.reflect.Field;

import java.lang.reflect.Method;
public class Vehicle {
    public static void main(String[] args)
        car c1 = new car();
        Class newcar1 = newcar1.getClass();
        Method m[] = newcar1.getDeclaredMethods();
        for (Method method : m)
        Field f[] = newcar1.getDeclaredFields();
        for (Field field : f)
//We can get details about a particular class by using the Class object.
class car {
    private String type;
    private int id_No;
    public String getType() { return type; }
    public void setType(String type) { this.type = type; }
    public int getId_no() { return id_No; }
    public void setId_no(int id_no)
        this.id_No = id_no;



Keep in mind that loading a ‘.class’ file only creates one instance of the class.

  • Linking: Executes three operations, including:
  1. Preparation: It allocates memory and initializes it to default settings for class variables.
  2. Verification: A file is correct as long as it has been correctly formatted and created by a valid compiler. The java.lang run-time exception is thrown when the verification fails. In this case, the component ByteCodeVerifier is responsible. After that, the class file is ready to be compiled.
  3. Resolution: There is a straightforward substitution for the sorts of symbolic references as the name suggests. Searching for the referenced entity in the method area is how it is accomplished.

Delegation-Hierarchy principle is used by JVM to load classes. Loading requests are delegated to extension classloaders, which in turn delegate requests to bootstrapping classloaders by system classloaders. Any other requests that are not routed through an extension class loader are routed through the system class loader (if found in the bootstrap path). As a last resort, java.lang run-time errors are thrown when the system class loader cannot load the class that was supplied.

JVM Memory

RAM can also be called the Runtime Data Area (RDA). There are various run-time data regions that must be present during the program’s execution, as specified by the JVM specification. When the JVM first starts, several of these objects are produced.

It’s possible to construct and destroy thread-specific objects. Thread-specific objects are generated and destroyed along with a thread, respectively.

It’s usually used to keep track of instructions.

In total, JVM is broken down into five sub-areas:

  1. Method area: Class information such as the class name, parent class name and methods are preserved in the method area.
  2. Heap area: In the heap area, all objects’ information is saved. There is also a Heap Area for each Java Virtual Machine and it’s also considered as a resource that’s shared.
  3. Stack area: Every block of this stack is termed an activation record/stack frame, and it stores method calls in each of the blocks there in. There is a frame for each local variable. JVM will destroy a thread’s run-time stack after it has terminated and due to this, it is not an accessible resource to the general public.
  4. PC registers: Store the address of the thread’s current instruction. Each thread has its PC Registers, as you might expect.
  5. Native method area: Every thread has its native stack that stores information about a native method’s parameters.

Execution engine

To run a .class file, you need an execution engine. For example, reading bytecode from a file, using data from various memory areas, then executing instructions.

It consists of the three components named below:

  1. Interpreter: Essentially, the interpreter takes bytecode and translates it to machine code. Interpreters may be faster at running one line of bytecode than they are at executing the entire code. Also, a fresh interpretation must be provided each time the same method is invoked.
  2. JIT Compiler (Just In Time compiler): Execution engines use the interpreter to execute byte code. The JIT compiler will be used instead of the execution engine to detect that a method is repeated.

JIT compiler consists of the following:

  • Intermediate Code Generator.
  • Code Optimizer.
  • Target Code Generator.
  • Profiler.
  1. Garbage Collector(GC): Objects that are not referenced can be removed by the garbage collector as a background process, freeing up space on the heap.

Java Native Interface (JNI)

Interacting with Native Method Libraries and providing native libraries (C, C++) for execution, a hardware-specific C/C++ library can call and be called from the JVM as a result.

Native Method Libraries are a set of native libraries (C, C++) that are required by the Execution Engine.


Virtual machines are not based on reality, but they can make you feel as though they are. When it comes time to compile Java code, the machines does so using the Java Virtual Machine and allows Java apps to run.

Happy learning!

Peer Review Contributions by: Lalithnarayan C