JVM Internals, Part 1 - Class Loader

A translation of the article was prepared specifically for students of the Java Developer course.








In this series of articles, I'll talk about how the Java Virtual Machine works. Today we look at the mechanism for loading classes in the JVM .



The Java Virtual Machine is at the heart of the Java technology ecosystem. It makes it possible for Java programs to implement the principle of “write once run everywhere”. Like other virtual machines, the JVM is an abstract computer. The main task of the JVM is to load class files and execute the bytecode contained in them.



The JVM includes various components, such as a Classloader , Garbage Collector (automatic memory management), an interpreter, a JIT compiler, and flow control components. In this article, we will look at the class loader.



The class loader downloads class files for both your application and the Java API. Only those Java API class files that are really required when running the program are loaded into the virtual machine.



The byte code is executed by the execution engine.







What is class loading?



Class loading is the search and loading of types (classes and interfaces) dynamically during program execution. Type data is in binary class files.



Class loading steps



The class loader subsystem is not only responsible for finding and importing binary class data. It also performs validation of imported classes, allocates and initializes memory for class variables, and helps in resolving symbolic links. These actions are performed in the following order:





Note - the class loader, in addition to loading classes, is also responsible for finding resources. A resource is some data (for example, a “.class” file, configuration data, images) that are identified using an abstract path separated by a “/” character. Resources are usually packaged with an application or library so that they can be used in application or library code.

Class loading mechanism in Java



Translator's note - this section describes the behavior for java <9, in java 9+ there have been small changes, which are described below.



Java uses the class loading delegation model. The basic idea is that each class loader has a “parent” loader. When a class is loading , the loader “delegates” the class search to its parent before searching for the class on its own.



The class loader delegation model is a graph of loaders that pass load requests to each other. The root of this graph is the bootstrap bootloader. Class loaders are created with one parent to whom they can delegate the load, and search for the class in the following places:





The class loader first checks to see if it has loaded the class before. If so, then the same class that was returned the last time is returned (the class stored in the cache). If not, the ability to load the class is provided to the parent. These two steps are repeated recursively in depth. If the parent returns null (or throws a ClassNotFoundException ), then the loader searches for the class on its own.



The class is loaded by the loader that is closest to the root, since the right to first load the class is always granted to the parent loader. This allows the loader to see only classes loaded independently by its parent or ancestors. It cannot see classes loaded by child loaders.



The Java SE Platform API has historically defined two class loaders:



Bootstrap class loader (basic, primary loader) - loads classes from bootstrap classpath.



System class loader - the parent class for new class loaders and, as a rule, the class loader used to load and run the application.



JDK 9+ Class Loaders



Application class loader - commonly used to load application classes from a classpath. It is also the default bootloader for some JDK modules that contain utilities or export the utilities API. ( Translator's note: for example, jdk.jconsole



, jdk.jshell



, etc.
)



Platform class loader - loads the selected (based on security / permissions) Java SE and JDK modules. For example, java.sql.



Bootstrap class loader - Loads the core Java SE and JDK modules.



These three built-in class loaders work together as follows:





To view the built-in class loaders, you can use the following code:



 package ru.deft.homework; import java.sql.Date; public class BuiltInClassLoadersDemo { public static void main(String[] args) { BuiltInClassLoadersDemo demoObject = new BuiltInClassLoadersDemo(); ClassLoader applicationClassLoader = demoObject.getClass().getClassLoader(); printClassLoaderDetails(applicationClassLoader); // java.sql classes are loaded by platform classloader java.sql.Date now = new Date(System.currentTimeMillis()); ClassLoader platformClassLoder = now.getClass().getClassLoader(); printClassLoaderDetails(platformClassLoder); // java.lang classes are loaded by bootstrap classloader ClassLoader bootstrapClassLoder = args.getClass().getClassLoader(); printClassLoaderDetails(bootstrapClassLoder); } private static void printClassLoaderDetails(ClassLoader classLoader) { // bootstrap classloader is represented by null in JVM if (classLoader != null) { System.out.println("ClassLoader name : " + classLoader.getName()); System.out.println("ClassLoader class : " + classLoader.getClass().getName()); } else { System.out.println("Bootstrap classloader"); } } }
      
      





By running this code on Amazon Corretto 11.0.3 installed on me, we get the following result:



 ClassLoader name : app ClassLoader class : jdk.internal.loader.ClassLoaders$AppClassLoader ClassLoader name : platform ClassLoader class : jdk.internal.loader.ClassLoaders$PlatformClassLoader Bootstrap classloader
      
      





You can learn more about the ClassLoader API here (JDK 11) .



All Articles