« November 2009
SunMonTueWedThuFriSat
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
     
       
Today
XML

Blog::Navigation

GetJava Download Button
Get the Source
Personal Blog

Blog::Referers

Today's Page Hits: 822

Powered by Roller Weblogger.
« Java "class"-ic... | Main | DTrace: Java method... »
20060313 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

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

To be continued...



( Mar 13 2006, 09:30:58 PM IST ) Permalink del.icio.us | furl | simpy | slashdot | technorati | digg

Comments:

Post a Comment:

Comments are closed for this entry.
Copyright (C) 2005, A. Sundararajan's Weblog