Java Class Loading…
Loading is the process of finding the binary representation of a class or interface type with a particular name and creating a class or interface from that binary representation.
Java class loading is basically reading the *.class
files from a source directory(directory location in the file system or in a network) and loading them in to the JVM/memory. From an Operating System’s perspective, compiled class file stored in the file system is binary. If JVM is to execute the logic written in byte code, it should first read these files in to the memory.
Java class loading happens only on-demand, dynamically. It doesn’t load all the class files in your classpath at the startup. Rather, only when one’s referred. This helps optimizing the memory usage. And once loaded, it will not be unloaded. That improves performance but indeed at the cost of memory. Big application with many classes could ultimately acquire large amount of memory, given that in the long run most of its classes will be utilized.
Class Loaders
- Bootstrap class loader
- Extension class loader
- Application/System class loader
Bootstrap(Primordial) Class Loader
Resides on top of the chain. Parent of them all. Still, you wouldn’t see that java.lang.ClassLoader
is extended by Bootstrap class loader. Because it’s a native class(written in C mostly) in the JVM. Implementation of the this class loader differs as per the underlying O/S’s architecture (It’s the platform dependent JVM which makes the Java byte code ‘compile once, run anywhere’). Given all the other class loaders themselves are Java classes, there has to be a loader to load them at the first place. Bootstrap loader does that.Responsible of loading the core libraries in the $JAVA_HOME/jre/lib/*
directory such as rt.jar
.
nipun@nipunt:/usr/lib/jvm/jdk1.8.0_151/jre/lib$ grep -ir . "ClassLoader.class"
Binary file rt.jar matches
nipun@nipunt:/usr/lib/jvm/jdk1.8.0_151/jre/lib$ grep -ir . "Launcher.class"
Binary file rt.jar matches
Extension Class Loader
Is responsible of loading classes from extension directories such as $JAVA_HOME/lib/ext
directory. Implemented inside the sun.misc.Launcher
as Launcher$ExtClassLoader
. This loader reads the java.ext.dirs
system property to get the locations to be queried. Therefore, any directory that is listed inside that mentioned system property will be queried for classes by the ExtClassLoader.
Application/System Class Loader
This class loader is used to launch the application. Reads the classes from the application’s class path (java.class.path
system property). You can also define it by passing -cp
or -classpath
arguments to the JVM.
Apart from those class loaders, you can also write your own class loader. May be in another post.
Principles of Class Loading
- Visibility :
Classes that are loaded by a parent class loader, are visible to child class loaders. Whereas parents can’t see the classes loaded by its child loaders.
If classC
is loaded byAppClassCloader
andC2
byExtClassLoader
, thenExtClassLoader
is unaware ofC2
. ButAppClassLoader
is aware of bothC
andC2
. - Uniqueness :
A class should not be re-loaded by a child loader, if it’s already been loaded by a parent loader. (But this doesn’t mean that you can’t load the same class twice. With two custom loaders which do not inherit one another might load the same class into two different name spaces.) - Parent Delegation :
Java class loaders have a hierarchy. A child class loader never tries to load the class by itself. It should check if it’s been already loaded. If so, no need of loading again.
Otherwise, it delegates the request to its immediate parent. This happens recursively until the request hits the Bootstrap loader. As it’s the parent of them all, now the Bootstrap loader gives a try to load the class. If it couldn’t, it delegates the request to the Extension loader. Likewise, the delegation effort is now propagated down the hierarchy. If, even the bottom most loader is unable to load the class, then we throw aClassNotFound
exception.
Below sample is to demonstrate some some class loadings.
Results of the above snippet would be as follows.
Hello World!
java.ext.dirs : /usr/lib/jvm/jdk1.8.0_151/jre/lib/ext:/usr/java/packages/lib/ext
com.sun.crypto.provider.AESKeyGenerator : sun.misc.Launcher$ExtClassLoader@5cad8086
Foo : sun.misc.Launcher$AppClassLoader@18b4aac2
String array : null
ArrayList : null
System argument java.ext.dirs
set to jre/lib/ext
and usr/packages/lib/ext
directories. Therefore, whatever the classes that are there, will be loaded by the Extension Class Loader. Such as AESKeyGenerator
. And this application’s Foo
class is loaded by the Application Class Loader. Arrays are loaded by Bootstrap Class Loader. That’s why it was printed as null
.
Leave a comment if you find anything should be corrected or added.
Cheers.
References
[1] https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-5.html
[2] https://www.baeldung.com/java-classloaders
[3] https://github.com/openjdk/jdk
[4] https://medium.com/platform-engineer/understanding-jvm-architecture-22c0ddf09722