Classloaders in JVM: An Overview
Classloaders are an essential part of the Java language itself. They are responsible for loading classes and resources into the JVM at runtime in Java.
Join the DZone community and get the full member experience.
Join For FreeClassloaders are an essential part of the Java Virtual Machine (JVM), but many developers consider them to be mysterious. This article aims to demystify the subject by providing a basic understanding of how class loading works in the JVM.
What Are Classloaders
In the Java Virtual Machine (JVM), classes are loaded dynamically and found through a process called class loading. Class loading is the process of loading a class from its binary representation (usually a .class file) into memory so that it can be executed by the JVM. This is where we need classloaders. Class loaders are used to load .class files into the memory.
How Classes Are Loaded in JVM
Classes are loaded in three steps:
Creation and Loading step. The first thing that happens is loading a class file using a class loader. There are two kinds of class loaders: the bootstrap class loader supplied by the JVM and user-defined class loaders. (More details about class loaders are in the next chapter) Then, an instance of
java.lang.Class
class is created and makes the class available to the JVM for further execution. A detailed step-by-step algorithm can be found in the Java Virtual Machine specification.Linking step before the class is ready for execution. The JVM needs to perform a number of preparatory operations, which include verification and preparation of the class for execution. The linking steps are the following:
Bytecode verification.
Verification ensures that the binary representation of a class or interface is structurally correct and is not corrupted. Otherwise, the class file will not be linked, and a VerifyError error will be thrown. Verification can be turned off by the
-noverify
option. Turning off the verification can speed up the startup of the JVM, but disabling bytecode verification undermines Java’s safety and security guarantees. Why not disable bytecode verification?Preparation.
Allocate RAM for static fields and initialize them with default values.
Resolution of symbolic links.
Since all references to fields, methods, and other classes are symbolic, JVM, in order to execute the class, you need to translate the references into internal representations.
Initialization step. After a class is successfully loaded and linked, it can be initialized. At this stage, the static class initializers or static variable initializers are called, which ensures that the static initialization block is executed only once and static variables are initialized correctly.
Also, it is worth remembering that Java implements delayed (or lazy) loading of classes. This means that class loading of reference fields of the loaded class will not be performed until the application explicitly refers to them. In other words, character reference resolution is optional and does not happen by default.
Classloader Features
Class loaders have three important features that are worth remembering:
- Delegation model: When requested to find a class or resource, a class loader will delegate the search for the class or resource to its parent class loader before attempting to find the class or resource itself.
- Visibility: Classes loaded by a parent class loader are visible to its child class loaders, but classes loaded by a child class loader are not visible to its parent class loaders or children.
- Uniqueness: In Java, a class is uniquely identified using
ClassLoader + Class
as the same class may be loaded by two different class loaders.Class A loaded by ClassLoader A != Class A loaded by ClassLoader B
It is helpful for defining different protection and access policies for different classloaders.
Classloaders Relationships
We should remember that classes in Java are loaded on demand. That is, the class is loaded only when is requested to.
As you know, the entry point of every program written in Java is public static void main(String[] args)
method. The main method is the place where the very first class is loaded. All the subsequently loaded classes are loaded by the classes which are already loaded and running.
When a class is requested by the running program, the System Class Loader searches for it in the application classpath. If the class is not found, the Platform Class Loader is searched, and if still not found, the Bootstrap Class Loader is searched.
If the requested class is found in a parent class loader, it is loaded by that class loader. If not, the System Class Loader loads the class. If the class has not been loaded before, the class loader loads it into memory and creates a new instance of the class object that represents the loaded class.
It is important to note that the class loading hierarchy is hierarchical in nature, with each class loader having a parent class loader. This parent-child relationship ensures that each class loader is responsible for loading only its own classes and delegates the loading of parent classes to its parent class loader.
Different Types of Classloaders
The class loading mechanist in JVM doesn’t use only one class loader. Every Java program has at least three class loaders:
- Bootstrap (Primordial) Class Loader: This is the root class loader and is responsible for loading core Java classes such as java.lang.Object and other classes in the Java standard library (also known as the Java Runtime Environment or JRE). It is implemented in native code and is part of the JVM itself. Although each class loader has its own
ClassLoader
object, there is no such object corresponding to the Bootstrap Class Loader. For example, if you would run this line of codeString.class.getClassLoader()
, you would getnull
. - Extension Class Loader: This class loader is responsible for loading classes from the extension directories (such as the jre/lib/ext directory in the JRE installation) and is a child of Bootstrap Class Loader. You can also specify the locations of the extension directories via the
java.ext.dirs
system property. - System (Application) Class Loader: This is the class loader that loads application-specific classes, usually from the classpath specified when running the Java application. The classpath can include directories, JAR files, and other resources. The classpath can be set using the CLASSPATH environment variable, the -classpath or -cp command-line option. The System/Application Class Loader is also implemented in Java and is a child of the Extension Class Loader.
Classloaders and Related to Them Changes Over Time
In the previous section, we’ve seen the class loaders hierarchy that was in Java until Java 9 revised that.
The new class loaders hierarchy since Java 9 looks like this:
- Bootstrap (Primordial) Class Loader: This is the root class loader and is responsible for loading core Java classes such as
java.lang.Object
and other classes in the Java standard library (also known as the Java Runtime Environment or JRE). It is implemented in native code and is part of the JVM itself. Although each class loader has its ownClassLoader
object, there is no such object corresponding to the Bootstrap Class Loader and, typically represented asnull
, and doesn’t have a parent. For example, if you would run this line of codeString.class.getClassLoader()
, you would getnull
. - Platform Class Loader (Former Extension Class Loader): All classes in the Java SE Platform are guaranteed to be visible through the Platform Class loader. Just because a class is visible through the platform class loader does not mean the class is actually defined by the Platform Class Loader. Some classes in the Java SE Platform are defined by the Platform Class Loader, while others are defined by the Bootstrap Class Loader. Applications should not depend on which class loader defines which platform class.
- System (Application) Class Loader: This is the class loader that loads application-specific classes, usually from the classpath specified when running the Java application. The classpath can include directories, JAR files, and other resources. The classpath can be set using the CLASSPATH environment variable, the -classpath or -cp command-line option. The System/Application Class Loader is also implemented in Java and is a child of the Extension Class Loader.
There are even more changes that were introduced in Java 9 which are related to class loaders, namely:
- The Application Class Loader is no longer an instance of
URLClassLoader
but rather an internal class. Now, there areClassLoaders
class that contains in itself an implementation of three built-in class loaders. Such as:- BootClassLoader
- PlatformClassLoader
- AppClassLoader
- However, the bootstrap class loader should be used via
BootLoader
class and not viaClassLoaders
class.
- However, the bootstrap class loader should be used via
- The Extension Class Loader has been renamed to the Platform Class Loader. The substantial difference between Java 8 Extension Class Loader and Java 9 Platform Class Loader is that the Platform Class Loader is no longer instance of
URLClassLoader
. But for the most part, the Platform Class Loader is the equivalent of what used to be known as the Extension Class Loader. One motivation for renaming it is that the extension mechanism has been removed, which we will discuss in the next paragraph. - Removed Extension Mechanism: In releases before Java 9, the extension mechanism allowed the runtime environment to find and load extension classes without explicitly mentioning them on the classpath. However, in JDK 9, this mechanism has been removed. To use extension classes, ensure that their JAR files are included in the classpath.
- Removed rt.jar and tools.jar
rt.jar
contains all of the compiled class files for the base Java Runtime environment.tools.jar
contains all tools that are needed by a JDK but not a JRE (javac, javadoc, javap).
Big thanks to Erik Pragt for reviewing and guiding me.
Opinions expressed by DZone contributors are their own.
Comments