Saturday, May 13, 2006

Java Hotspot VM : Server Or Client

As a developer, if you have installed a JDK (Java Development Kit)1 downloaded from java.sun.com, you might have noticed that there are two versions of Java Hotspot VM to use. They are JIT (Just-in-Time) compilers for the Java Interpreter to improve the performance of the targeted applications. Broadly there are two types of application - client or server, thus there are two versions of Java Hotspot VM - Client and Server. These two options should not be confused with that the Client VM can communicate with the Server VM. One instance of a Java VM can use2 either a Client or Server Hotspot VM.

The Hotspot (or JIT) compiler technology is the one which boosts the Java performance by interfacing the Java platform and the actual underlying platform. Hotspot provides comparable performance with native applications as the optimization is done on-the-fly, during runtime.

Both are implemented as separate binaries (windows: %JAVA_HOME%\bin\{client|server}; solaris & linux: $JAVA_HOME/lib/$ARCHITECTURE/{client|server}). The Java launcher (${JAVA_HOME}/bin/java[.exe]) chooses the required hotspot VM based on the command line arguments. Though there are two hotspot VMs available, a developer cannot target his Java code for a particular3 VM. Java byte-code is 100% compatible with both the hotspot VMs.
% java -client -version
Java HotSpot(TM) Client VM (build 1.5.0_06-b05, mixed mode, sharing)
A Hotspot Client VM is suitable for any short-lived applications like a Java Applet in a web browser or UI application on desktops. Client VM makes the application load faster, does few optimizations compared to Server VM, identifies a hotspot (code that is used heavily by the application which can be optimized) very sooner than the Server VM. Also it uses different set of GC (garbage collection) algorithms than the Server VM. With tiger (1.5.0), Client JVM started sharing the core classes between instances by Class Data Sharing feature. This speeds up the application startup and reduces the memory footprint. The -version output above gives the information whether the JVM is using shared classes sharing. This is not available for Server VM.
% java -server -version
Java HotSpot(TM) Server VM (build 1.5.0_06-b05, mixed mode)
Server VM is best suitable for all long running applications like Application Servers, Web Servers and so. This class VM does more levels optimizations enabled the server applications run faster. With a long running Java process, the amount of garbage created is also very high and proportionate to the heap size (-Xms, -Xmx). With very big heaps, the GC might need more time to clean up. To overcome such issues, Server VM comes with many GC algorithms to choose from. There is also verity of flags and command line options available to fine tune the GC.

There is also an option available to disable both the hotspot VMs. Use -Xint (interpreter mode) . Please note that this also requires any one of the hotspot VM's interpreter, if nothing is specified the default one is used.
% java -Xint -server -version
Java HotSpot(TM) Server VM (build 1.5.0_06-b05, interpreted mode)
Most downloaded configurations of a JRE (Java Runtime Environment) for Windows will have only Client Hotspot VM, unless the platform does not have a client VM.

To change the default VM, move your default choice in the file $JAVA_HOME/lib/$ARCHITECTURE/jvm.cfg to be the first uncommented line.


1. JDK has been known in many forms: JavaTM 2 Platform Standard Edition Development Kit 5.0 with '1.5.0' or 'tiger', J2SE Software Development Kit with '1.4.2' or 'mantis', Java SE Development Kit 6 (the next major release - 'mustang').

2. JVM can also run without any of the Hotspot VM, i.e., it can run as interpreter alone. To do that use -Xint as the command line argument.

3. Due to different optimizations being used by both VMs, reproducing some bug might be different in different hotspot VM. This is purely a runtime issue and not a development time or deployment time issue.

Wednesday, May 10, 2006

Java ClassLoader : ClassNotFoundException Or NoClassDefFoundError

Java Virtual Machine loads the required classes (class could be a Java class or Java interface) through chain of class loaders. When a class is getting loaded there are possible cases where one can get an Exception or Error. This article might give some basics in handling these situations.

First, let's see the possible exceptions or errors that could raise during a class loading process :

java.lang.Exception
+->java.lang.ClassNotFoundException
java.lang.LinkageError
+->java.lang.NoClassDefFoundError
+->java.lang.ClassCircularityError
+->java.lang.ClassFormatError
+->java.lang.VerifyError
+->java.lang.IncompatibleClassChangeError
| +->java.lang.InstantiationError
| +->java.lang.AbstractMethodError
+->java.lang.ExceptionInInitializerError
java.lang.VirtualMachineError
+->java.lang.OutOfMemoryError

The most common exception or errors would be: ClassNotFoundException and NoClassDefFoundError. Both means the same information - not able to load a given class (or interface) from the known classpath. Then, why two types ?

Exception is something which a programmer should anticipate during his program execution. Which means - the code can fail, but should be able to recover from that using exception handlers. How can it happen ? The answer is - when using Java API (Application Programming Interface) to find and load the class. Java API provides java.lang.Class.forName(), using which a programmer can request the ClassLoader to find and load (if not already done) a class by providing it's String name.
From the API specification, Class.forName() can throw any one of these when it is not able to find and load the requested class: ClassNotFoundException and LinkageError (any subclass of it).

Class c = null;
try {
c = Class.forName("AVeryNewClassName");
info.log("Using custom settings...");
} catch(ClassNotFoundException handle) {
// handle the exception
info.log("Using default settings...");
c = DEFAULT_CLASS;
}

On the other hand a programmer should not anticipate an Error in his program execution. Though some errors are catchable, it is not advisable. The reason being, the Java VM has identified it as an Error and it's internal state may get affected if the program continues to run with that error. When the JVM is very sure about the Error, it gives out the message and shuts down itself. OutOfMemoryError is a good example. When JVM decides that there is no space for any new object, it gives out the message and comes down.

The following code uses a class which was available during the compilation of this class, but not available during runtime. This throws NoClassDefFoundError. Here there is no API being used to construct the class or instance of it. This line (new operator) requires the class to be loaded and initialized to create an instance of it. Thereby this statement has to throw an Error, which should not be caught. NoClassDefFoundError is a subclass of LinkageError, meaning that this error has occurred during linking a class.

CompileTimeOnlyClass c = new CompileTimeOnlyClass();
or
CompileTimeOnlyClass.invokePublicStaticMethod();


Internally, JVM uses ClassLoaders to search a class and recieves the ClassNotFoundException. This will get converted into NoClassDefFoundError, if the class loading operation is initiated by the JVM. You would get the same error if you run the following command:

% java NotYetCompiledClass
Exception in thread "main" java.lang.NoClassDefFoundError: NotYetCompiledClass