If someone asks you what class loaders are, you
would probably say with a smile on your face, well!! they load classes in to
JVM. And you would probably go on to explain what the perm gen space is and how
it would run out if you got too many classes hogging it. It's not serious
business, you might think, the chances are that you have gone through all your
life not intefering with them. Its like that weird kid in the class, you don't
mess with. He does his business you do yours, but sooner or later you gonna
have to talk to him. Well class loaders are like that.
How many times have you hot deployed a web
application and gotten the dreaded out of memory error, and how many times have
you cursed before restarting to get it working again. Well the problem I am
afraid does not lie in the application server (obviously), its how you have
written your code. Do you ever look to see what the problem really is, well most
people choose not to.
Now before we go any further let's see what class
loaders do.
Class loaders do a pretty important job, when
you compile your application you turn your java code into bytecode and save it
in .class files, you go a step further and bind your .class files in to a jar.
That's all good. Now when you want to use the classes in this jar file, you
invariably add it to the class path of the application in question. And viola,
you can use those classes in your application now. What happens here is not
magic. Your .class files are, behind the scenes being loaded on to the JVM by
classloaders.
Let’s see when classes are being loaded in to
JVM.
Classes are loaded when you create instances of them, or when you make a static reference using a dot notation, loading classes
is done on demand. Curious minds would inquire now how the references classes
are loaded, well they are loaded along with your main class, but what about
when you have multiple classes declaring instances of the same class, well
class loaders keep caches of the classes they load hence if the class you
require is already loaded they won’t load it again there's a catch here though. This brings us to an interesting
revelation, how does the situation change when you have multiple class loaders.
Multiple unrelated (isolated) class loaders can load the same class so that it’s
possible for multiple instances of the same class to exist in the JVM and the funny thing is they
will never be equal.
You might ask, what of that singleton class I wrote
last week, I was so proud of, well what of it, your singletonness is guaranteed
only to the class loader that loads it. How to protect your singleton from
being loaded twice in to JVM by multiple class loaders is a question that begs
a separate blog post. In short you basically need to write your own class loader
or make sure you always chain your custom class loaders so that they always
have a common parent.
Let’s now move on to types of class loaders in
Java of which there are mainly three.
- Bootstrap Class Loader
- Extensions Class Loader
- System Class Loader
Bootstrap class loader loads Java Core classes
typically present in jre/lib folder, while extensions class loader as you may
have guessed already load Java extensions typically present in jre/lib/ext you
can also define your ext locations by setting the system property “java.ext.dir”.
Systems class loader loads classes from the class path defined, you can also
define this using “java.class.path” System variable.
And of course you can write your own custom class
loaders, do this if you are pretty finicky, well most Java geeks like to be very
hands-on. What you also need to understand is that these class loaders are
executed in the order listed, first the bootstrap, then extensions and finally system
which is implemented by sun.misc.Launcher$AppClassLoader.
When Java
code is compiled by the compiler, the complier adds a static final field called
“class”, every class has it. And why I brought this seemingly irrelevant
subject here is because using this property you can get the class loader which
loaded the class, this is pretty handy. You can try this out with a class you
wrote, the interesting this to note here that you can go up the hierarchy to
access the parent class loaders, when you get null, is when you know you have
hit the bootstrap class loader, because bootstrap class loader always returns
null.
Before I wrap this post up, let me list the
steps a class loader has to go through before loading a class in to JVM, important
if you are writing your own
1.
Verify Class Name
Important if you write your
own class loader, you don’t want people to use your class loader to load
classes you didn’t intent to.
2.
Check to see if it has been
loaded already
If the class is loaded, which
it tracks by using a map of some sort, return the class already loaded
3.
Check to see if the class
is a systems class
If it is then the chances
are that it’s already loaded, don’t take chances through, pass control to your
parent class loader.
4.
Attempt to fetch the class
from the class loader repository
This is where the actual
loading happens, your repository may reside over a network, or a separate folder,
load your classes as a byte stream.
5.
Define the class for the JVM
First step is to verify
that the byte code is valid, if not throw a class format error
6.
Resolve the class
What this means is that you need to load the
references (any classes that the class you are trying load is using) you also
need to verify the legitimacy of these references, failing this step is what
leads to the infamous Linkage Errors
7.
Return the class to the
caller
Finally return your class to the caller. Ill show you in another post how to write your own class loader.
And that’s a wrap.