JVM Architecture

Srikanth Dannarapu
Javarevisited
Published in
8 min readMar 7, 2023

JVM (Java Virtual Machine) is a software that interprets and executes Java code. Here’s a simple way to understand its architecture:

  • The JVM consists of three main components: the class loader, the runtime data area, and the execution engine.
  • The class loader is responsible for loading classes into the JVM. When you run a Java program, the class loader searches for the necessary classes and loads them into the runtime data area.
  • The runtime data area is where the JVM stores data during program execution. It consists of several different areas, including the method area (where class and method information is stored), the heap (where objects are stored), and the stack (where method calls and local variables are stored).
  • The execution engine is responsible for executing the bytecode (compiled Java code) that is loaded into the JVM. The execution engine reads the bytecode and performs the necessary operations to carry out the program’s instructions.
  • The JVM also includes a garbage collector, which automatically frees up memory that is no longer being used by the program.
JVM Architecture

Class Loader:

In Java, there are three types of class loaders that are responsible for loading classes into the JVM: the Bootstrap Class Loader, the System Class Loader, and the Extension Class Loader. Here is a simple explanation of each type:

  1. Bootstrap Class Loader: The Bootstrap Class Loader is the first class loader to load classes when the JVM starts up. It loads the core Java API classes (such as java.lang.String) from the rt.jar file located in the Java runtime environment. It is implemented in native code and is responsible for loading the core Java libraries, which are required for the JVM to function. The Bootstrap Class Loader is an integral part of the JVM and cannot be replaced or modified by the user.
  2. System Class Loader: The System Class Loader, also known as the Application Class Loader, is responsible for loading classes from the classpath specified by the user. It is implemented in Java and is responsible for loading the classes from the application codebase. The classpath is a list of directories and JAR files where the System Class Loader searches for classes. For example, when you run a Java program using the “java” command, the System Class Loader loads the classes from the specified classpath.
  3. Extension Class Loader: The Extension Class Loader is responsible for loading classes from the extensions directory, which contains JAR files with third-party extensions to the Java platform. The extensions directory is specified by the java.ext.dirs system property, and the Extension Class Loader loads the classes from JAR files located in this directory. For example, if you use a third-party library that extends the functionality of the Java platform, the Extension Class Loader will load the classes from the JAR file containing that library.

Here’s a simple example that illustrates how the different class loaders work together:

Suppose you have a Java program that uses a third-party library called “commons-lang.jar”. When you run the program, the following happens:

  1. The Bootstrap Class Loader loads the core Java API classes from the rt.jar file.
  2. The Extension Class Loader loads any classes from the extensions directory that are required by the program or the third-party library. In this case, it would load the classes from “commons-lang.jar”.
  3. The System Class Loader loads any classes from the classpath that are required by the program. This includes the main class of the program and any classes that it depends on.

By using these three class loaders, Java is able to load classes from different sources and provide a flexible runtime environment.

Runtime Data Area:

The runtime data area is the memory area where data is stored during program execution. It is divided into several different areas, each with its own purpose. Let’s take a look at an example program to understand how memory is allocated in the runtime data area.

Suppose we have the following Java program:

public class ExampleProgram {
public static void main(String[] args) {
int a = 10;
String message = "Hello, world!";
System.out.println(message + " The value of a is: " + a);
}
}

When this program is executed, the JVM will allocate memory in the runtime data area to store the program’s data. Here’s how the memory might be allocated:

  • Method area: The method area is where the JVM stores class and method information. In our example program, the method area would store information about the ExampleProgram class and its main method.
  • Heap: The heap is where objects are stored. In our example program, the String object containing the message "Hello, world!" would be stored on the heap.
  • Stack: The stack is where method calls and local variables are stored. In our example program, the main method would be added to the stack when it is called. The int variable a would also be allocated on the stack, along with a reference to the String object containing the message.
Memory Allocation

Here’s a simplified diagram showing how memory might be allocated in the runtime data area:

Method area:
- ExampleProgram class
- main method

Heap:
- String object ("Hello, world!")

Stack:
- main method
- int variable a (value = 10)
- String reference variable message (points to the String object on the heap)

As the program runs, the execution engine will read the bytecode and perform the necessary operations on the data stored in the runtime data area. When the program is finished executing, the memory in the runtime data area will be released. The garbage collector will automatically free up any memory that is no longer being used by the program.

Garbage Collector (GC)

The Garbage Collector (GC) is an integral part of the Java Virtual Machine (JVM) that automatically manages the allocation and release of memory used by Java programs. Here’s a more detailed explanation of how the garbage collector works:

When a Java program runs, it creates objects and variables that are stored in memory. The garbage collector constantly monitors the memory usage of the program, and identifies objects that are no longer needed or being used. These objects are referred to as “garbage” and need to be removed from memory to free up space for new objects.

The garbage collector uses a process called “mark and sweep” to identify and remove garbage objects. The process works as follows:

  1. Marking: The garbage collector identifies all objects that are still in use by the program. It starts at the root objects (such as static variables or objects currently being executed) and recursively follows all references to other objects in memory. Any objects that are not reachable by this process are considered garbage.
  2. Sweeping: The garbage collector removes all objects that are not marked as in-use. This frees up memory that can be used for new objects.
Garbage Collector

The garbage collector can run at any time during the execution of a program. It runs in the background, without any input or control from the program itself. This means that the garbage collector is able to automatically manage the allocation and release of memory without any intervention from the programmer.

There are several different types of garbage collectors available in the JVM, each with its own strengths and weaknesses. The most commonly used garbage collector is the “parallel collector”, which uses multiple threads to perform garbage collection in parallel, making it faster and more efficient. Other types of garbage collectors include the “concurrent collector”, which performs garbage collection while the program is still running, and the “G1 collector”, which is optimized for large heaps.

One potential drawback of garbage collection is that it can occasionally cause “pauses” in program execution while the garbage collector runs. During these pauses, the program cannot execute any code, which can lead to performance issues in time-critical applications. However, modern garbage collectors have become very efficient and generally cause only minor pauses that do not significantly impact program performance.

Type of GC

There are several different types of garbage collectors available in the Java Virtual Machine (JVM), each with its own strengths and weaknesses. Here’s a brief explanation of the most common types:

  1. Serial Collector: This is the simplest garbage collector, and is suitable for use on small applications that run on single-core machines. It works by pausing the application while it performs garbage collection, which can cause noticeable performance issues for larger applications.
  2. Parallel Collector: The parallel collector uses multiple threads to perform garbage collection in parallel, making it faster and more efficient than the serial collector. It is suitable for use on larger applications running on multi-core machines, and can be configured to use more or fewer threads depending on the available resources.
  3. Concurrent Mark Sweep (CMS) Collector: This collector is designed to minimize pauses during garbage collection, allowing the application to continue running while garbage collection is being performed. It works by breaking the garbage collection process into smaller steps, and interleaving those steps with application code. This collector is suitable for use on large applications with limited pause time requirements.
  4. G1 Collector: The G1 collector is a newer collector that is optimized for large heaps (i.e. applications that use a lot of memory). It works by dividing the heap into multiple regions, and performing garbage collection on those regions that contain the most garbage. This collector is designed to minimize pause times and can be used on applications of various sizes.
  5. Z Garbage Collector: This is a newer collector that is optimized for low-pause time and high-throughput requirements. It works by using a different approach to memory management, which allows it to minimize the amount of time spent on garbage collection. It is suitable for use on large applications with stringent pause time requirements.
Type of GC

Overall, the choice of garbage collector will depend on the specific requirements of the application. Different garbage collectors will perform better or worse depending on factors such as the size of the heap, the number of threads available, and the desired pause time. By understanding the strengths and weaknesses of each type of garbage collector, programmers can choose the best option for their specific application.

Thanks, before you go:

  • 👏 Please clap for the story and follow the author 👉
  • Please share your questions or insights in the comments section below. Let’s help each other and become better Java developers.
  • Let’s connect on LinkedIn

--

--