Imagine a bacon-wrapped Ferrari. Still not better than our free technical reports.

My class loader hates me and wants to slow me down

In this post, we look at how during developing Java applications, one typically needs to waste time rebuilding the project and restarting the application server every time they want to see the change they introduced to the code reflected in the running app, which is all the time. We discuss how Java loads the classes and why classloaders hierarchy means it’s not easy to alleviate them of wasting time on rebuilding and redeploying you app.

When dealing with Java application development, you go through several actions over and over again. The same is mostly true for any technology stack. To implement a change in the app, you first need to code it up, then run the application and verify that the changes you just implemented are truly what you wanted them to be — functionally correct and working. The problem is that the latter can take quite some time, especially with the Java stack. You typically need to build your project, either fully or partially, tear down and restart the Java process running your code and load or deploy your application again.

Two of these phases are irrelevant to implementing the changes. Building, packaging and deploying is not necessary — rather an artifact of the platform than a necessity. It would be much faster and easier if we could just reload the classes in the JVM with the new class definitions. This way, when the JVM accesses the classes or objects of the changed classes next time, new code would already be in there. It would save a lot of development time currently wasted.

The Problem

Let’s talk about how Java loads your application classes to execute its code. Once a Java class has been loaded by a class loader, it’s immutable and will last as long as the class loader itself. The identity is the class name and class loader identity, so to reload an application, you’ll need to create a new class loader which in turn will load the latest version of the app classes. You can’t map an existing object onto a new class, so it’s important to migrate state across around reloads. It could mean recreating the whole application object graph by reinitializing the application and config state etc. or copying over user session state. Very often this is also time-consuming and is very vulnerable to memory leaks.
When dealing with memory leaks with class loaders, a small one line leak can be amplified by the reference model Java uses. For instance, a class loader instance will have a reference to all classes it loads and all instances of the objects that are then created. So even a small leak, perhaps added in state migration between application instances during a reload, can, in fact, have much larger repercussions.
So, what does this mean for you as a developer? It means constant compilation, build, packaging, re-deployment, and application server restarts that just get in the way of your focus and your interesting, productive work that you want to get on with.

Let’s look at class loaders

A class loader is just a plain java object. Yes, it’s nothing clever, well other than the system class loader in the JVM, a class loader is just a java object! It’s an abstract class, ClassLoader, which can be implemented by a class you create. Here is the API:

public abstract class ClassLoader {
  public Class loadClass(String name);
  protected Class defineClass(byte[] b);
  public URL getResource(String name);
  public Enumeration getResources(String name);
  public ClassLoader getParent();
}

Looks pretty straightforward, right? Let’s take a look method by method. The central method is loadClass which just takes a String class name and returns you the actual Class object. This is the method which if you’ve used class loaders before is probably the most familiar as it’s the most used in day to day coding. defineClass is a final method in the JVM that takes a byte array from a file or a location on the network and produces the same outcome, a Class object.
A class loader can also find resources from a classpath. It works in a similar way to the loadClass method. There are a couple of methods, getResource and getResources, which return a URL or an Enumeration of URLs which point to the resource which represents the name passed as input to the method.
Every class loader has a parent; getParent returns the class loader’s parent, which is not Java inheritance related, rather a linked list style connection. We will look into this in a little more depth later on.
Class loaders are lazy, so classes are only ever loaded when they are requested at runtime. Classes are loaded by the resource which invokes the class, so a class, at runtime, could be loaded by multiple class loaders depending on where they are referenced from and which class loader loaded the classes which referen… oops, I’ve gone cross-eyed! Let’s look at some code.

public class A {
  public void doSmth() {
    B b = new B();
    b.doSmthElse();
  }
}

Here we have class A calling the constructor of class B within the doSmth method. Under the covers this is what is happening

A.class.getClassLoader().loadClass("B");

The class loader which originally loaded class A is invoked to load the class B.

Class loaders are hierarchical, but like children, they don’t always ask their parents

Every class loader has a parent class loader. When a class loader is asked for a class, it will typically go straight to the parent class loader first calling loadClass which may, in turn, ask it’s parent and so on. If two class loaders with the same parent are asked to load the same class, it would only be done once, by the parent. It gets very troublesome when two class loaders load the same class separately, as this can cause problems which we’ll look at later.

When Java EE application servers implement the Java EE spec, some prefer to delegate to the parent always, but others choose to look locally within the Web App class loader first. Let’s go into this in more depth and use figure 1 as our example.

Figure 1

In this example, Module WAR1 has its own class loader and prefers to load classes itself rather than delegate to its parent, the class loader scoped by App1.ear. It means different WAR modules, like WAR1 and WAR2 cannot see each other’s classes. The App1.ear module has its own class loader and is the parent to the WAR1 and WAR2 class loaders. The App1.ear class loader is used by the WAR1 and WAR2 class loaders; they use it when to delegate a class loading call up the hierarchy i.e. when the required class is outside of the WAR scope.

Effectively the WAR classes override the EAR classes where both exist. Finally, the EAR class loader’s parent is the container class loader. The EAR class loader will delegate requests to the container class loader, but it does not do it in the same way as the WAR class loader, as the EAR class loader will prefer to delegate up rather than prefer local classes. As you can see this is getting quite hairy and is different to the normal Java class loading behavior.

So how do we reload classes in this application?

We know from looking at the ClassLoader API earlier that you are only able to load classes. That is to say, there’s no way to unload or reload classes, so to recreate a class at runtime you have to throw away the entire class hierarchy structure and recreate it to load and use the new class, as shown in Figure 2.

reloading-object
Figure 2

If you have programmed in Java for some time you know that memory leaks do happen. Usually, it’s the case of a collection somewhere with references to objects (e.g. listeners) that should have been cleared, never were. Class loaders are a very special case of this, and unfortunately, with the current state of the Java platform, these leaks are both inevitable and costly: routinely causing OutOfMemoryErrors in applications after a small number of redeploys.
Every object had a reference to its class, which in turn had a reference to its class loader. The key part though is that every class loader, in turn, has a reference to every class it has ever loaded, each of which holds static fields defined in the class as shown in figure 3:
classloader-refs
Figure 3

If a class loader is leaked it will hold on to all its classes and all their static fields. Static fields commonly hold caches, singleton objects, and various configuration and application states. Even if your application doesn’t have any large static caches, it doesn’t mean that the framework you use doesn’t hold them for you (e.g. Log4J is a common culprit as it’s often put in the server classpath). This explains why leaking a class loader can be so expensive.

To leak a class loader it’s enough to leave a reference to any object, created from a class, loaded by that class loader. Even if that object seems completely harmless (e.g. doesn’t have a single field), it will still hold on to its class loader and all the application state. A single place in the application that survives the redeploy and doesn’t do a proper cleanup is enough to sprout the leak. In a typical application, there will be several such places, some of them almost impossible to fix due to the way third-party libraries are built. Leaking a class loader is, therefore, quite common.


So it is the technical problem under the covers which means to refresh our code at runtime, we typically need to build, package, re-deploy and even restart our containers to see our updated code. However time-consuming that it.
Also, since the classloading process is so essential to the Java platform and lies at the core of everything, it cannot be easily resolved from within the platform.

The best effort to deal with reloading the classes that comes with the platform is HotSwap. It was incorporated within the Debugger API, and allowed debuggers to update class bytecode in place, using the same class identity. This meant that all objects could refer to an updated class and execute new code when their methods were called, preventing the need to reload a container whenever class bytecode was changed. Unfortunately, HotSwap’s class redefinition is limited to changing method bodies only. It cannot add methods or fields or otherwise change anything else, except for the method bodies. This severely limits the usefulness of HotSwap, leaving the problem of wasting time on rebuilding your application unsolved.


JRebel is a tool that can reload your Java application classes at runtime. If you’d like to see a bit more about what JRebel is capable of, join us on these product pages and click this button here:

Or watch the recording of the “ZT Master Class: Intro to JRebel” where we answer the questions about how JRebel works and how you can start using it.

 

  • Bipin Pandey

    Very Interesting…can you provide link to the follow-up article?