X
  • Java |
    Monday, March 13, 2006

Understanding Java class loading

Understanding Java class loading

Are you thinking of writing ClassLoaders? or are you facing
"unexpected" ClassCastException or LinkageError with wierd message
"loader constraint violation". Then, it is time to take a closer look
at Java class loading process.

What is a ClassLoader and how it loads?

A Java class is loaded by an instance of java.lang.ClassLoader class.
java.lang.ClassLoader itself is an abstract class and so a class loader can only an instance
of a concrete subclass of java.lang.ClassLoader. If this is the case, which class loader loads
java.lang.ClassLoader class itself? (classic "who will load the loader" bootstrap issue).
It turns out that there is a bootstrap class loader built into the JVM. The bootstrap
loader loads java.lang.ClassLoader and many other Java platform classes.

To load a specific Java class, say for example com.acme.Foo, JVM invokes loadClass
method of a java.lang.ClassLoader (actually, JVM looks for loadClassInternal method - if found
it uses that method, or else JVM uses loadClass. And loadClassInternal method calls loadClass).
loadClass receives name of the class to load and returns java.lang.Class instance that represent
the loaded class. Actually, loadClass method finds the actual bytes of .class file (or URL) and calls
defineClass
method to construct java.lang.Class out of the byte array. Loader on which loadClass is called is referred
as initiating loader (i.e., JVM initiates loading using that loader). But, the initiating loader
need not directly find the byte[] for class - instead it may delegate the class loading to
another class loader (for example, to it's parent loader) -
which itself may delegate to another loader and so on. Eventually some
class loader object in delegation chain ends up calling defineClass method to actually load the concerned class (com.acme.Foo).
That particular loader is called defining loader of com.acme.Foo. At runtime, a Java class is uniquely
identified by the pair - the fully qualified name of the class and the defining loader that loaded it.
If the same named (i.e., same fully qualified name) class is defined by two different loaders, these classes
are different - even if the .class bytes are same and loaded from the same location (URL).

How many classloaders and where they do load from?

Even with a good old simple "hello world" Java program, there are atleast 3 class loaders.


  1. bootstrap loader
    • loads platform classes (such as java.lang.Object, java.lang.Thread etc)
    • loads classes from rt.jar ($JRE_HOME/lib/rt.jar)
    • -Xbootclasspath may be used to alter the boot class path
      -Xbootclasspath/p: and -Xbootclasspath/a: may be used to prepend/append
      additional bootstrap directories - have extreme caution doing so. In most
      scenarios, you want to avoid playing with boot class path.
    • In Sun's implementation, the read-only System property sun.boot.class.path
      is set to point to the boot class path.Note that you can not change
      this property at runtime - if you change the value that won't be effective.
    • This loader is represented by Java null. i.e., For example,
      java.lang.Object.class.getClassLoader()
      would return null (and so for other bootstrap classes such as java.lang.Integer, java.awt.Frame, java.sql.DriverManager etc.)
  2. extension class loader
    • loads classes from installed optional packages
    • loads classes from jar files under $JRE_HOME/lib/ext directory
    • System property java.ext.dirs may be set to change the extension directories
      using -Djava.ext.dirs command line option.
    • In Sun's implementation, this is an instance of sun.misc.Launcher$ExtClassLoader (actually it is an inner class
      of sun.misc.Launcher class).
    • Programmatically, you can read (only-read!) System property java.ext.dirs to find
      which directories are used as extension directories. Note that you can not change
      this property at runtime - if you change the value that won't be effective.
  3. application class loader
    • Loads classes from application classpath
    • Application classpath is set using
      • Environment variable CLASSPATH (or)
      • -cp or -classpath option with Java launcher

      If both CLASSPATH and -cp are missing, "." (current directory) is used.
    • The read-only System property java.class.path has the value of
      application class path. Note that you can not change this property at runtime -
      if you change the value that won't be effective.
    • java.lang.ClassLoader.getSystemClassLoader()
      returns this loader
    • This loader is also (confusingly) called as "system class loader"
      - not to be confused with bootstrap loader which loads Java "system" classes.
    • This is the loader that loads your Java application's "main" class (class with main method in it).
      In Sun's implementation, this is an instance of sun.misc.Launcher$AppClassLoader (actually it is an inner class
      of sun.misc.Launcher class).
    • The default application loader uses extension loader as it's parent loader.
    • You can change the application class loader by command line option -Djava.system.class.loader. This value
      specifies name of a subclass of java.lang.ClassLoader class. First the default application
      loader loads the named class (and so this class has to be in CLASSPATH or -cp) and creates
      an instance of it. The newly created loader is used to load application main class.

Typical class loading flow

Let us assume you are running a "hello world" java program. We will how class loading proceeds. JVM loads main class using
the "application class loader". If you run the following program


class Main {

public static void main(String[] args) {
System.out.println(Main.class.getClassLoader());javax.swing.JFrame f = new javax.swing.JFrame();
f.setVisible(true);SomeAppClass s = new SomeAppClass();

}
}

it prints something like
sun.misc.Launcher$AppClassLoader@17943a4

Whenever a reference to some other class has to be resolved from Main class, then JVM
uses the defining loader of Main class - the application class loader - as initiating loader.
In the above example, to load the class javax.swing.JFrame, JVM will use the application
class loader as initiating loader. i.e., JVM will call loadClass() (loadClassInternal) on
the application class loader. The application class loader delegates that to extension
class loader. And the extension class loader checks whether it is a bootstrap class
(using a private method - ClassLoader.findBootstrapClass) and the bootstrap loader
defines the class by loading it from rt.jar. When reference to SomeAppClass has to be resolved,
JVM follows the same process - it uses application class loader as initiating loader for
it. The application loader delegates it to extension loader. Extension loader checks with
bootstrap loader. Bootstrap loader won't find "SomeAppClass". Then extension loader checks
whether "SomeAppClass" is in any of the extension jars and it won't find any. Then application
class loader check the .class bytes in application CLASSPATH. If it finds, it defines
the same. If not, NoClassDefFoundError will be thrown.

Summary

  • Class is uniquely identified by defining loader and fully qualified name.
  • Classes are different even if loaded from identical .class bytes from the same
    location in file system, if the defining loaders are different.
  • Class loaders delegate loading to parent loaders.
  • To load class "Foo" referrred from "Bar" class, JVM uses Bar's defining loader
    as initiating loader. JVM will call loadClass("Foo") on the defining loader of Bar.
  • JVM caches -> runtime class record for each time
    it initiates a load. JVM will use cache for subsequent resolution. i.e, loadClass won't
    be called for every reference. This ensures time invariance - i.e., a ClassLoader that
    loads different .class bytes for the same class name won't be allowed. It is taken care
    by cache. Well written class loaders have to check cache by ClassLoader.findLoadedClass()
    call.

Stay tuned for more discussion on loader constraints and LinkageErrors..


To be continued...

Be the first to comment

Comments ( 0 )
Please enter your name.Please provide a valid email address.Please enter a comment.CAPTCHA challenge response provided was incorrect. Please try again.Captcha
Oracle

Integrated Cloud Applications & Platform Services