Home/Learn/Java A–Z/Class Loading and Hot Reload

Class Loading and Hot Reload

Advanced
JVM Internals

Deep dive into class loading mechanics — custom loaders, hot reload, isolation, and the role class loaders play in frameworks.

Overview

Every class in the JVM is identified by its fully-qualified name AND the ClassLoader that loaded it. Two classes with the same name loaded by different ClassLoaders are distinct types. This mechanism enables hot reload (OSGi, Spring DevTools, JRebel), plugin isolation, and multi-tenancy. Understanding this is essential for framework development, debugging ClassCastExceptions between loaders, and building dynamic systems.

Parent Delegation and Loader Identity

The parent delegation model: when a class loader is asked to load a class, it first asks its parent. Only if the parent cannot find it does the child try. This prevents malicious code from replacing java.lang.String by loading it from the classpath.

Class identity = class name + ClassLoader. Two instances of the same class loaded by different loaders cannot be cast to each other.

LoaderIdentity.java
// Two loaders — two identities
ClassLoader loader1 = new URLClassLoader(urls);
ClassLoader loader2 = new URLClassLoader(urls);

Class<?> cls1 = loader1.loadClass("com.example.Plugin");
Class<?> cls2 = loader2.loadClass("com.example.Plugin");

System.out.println(cls1 == cls2); // FALSE — different identities!

// ClassCastException across loaders
Object obj = cls1.getDeclaredConstructor().newInstance();
// com.example.Plugin cast = (com.example.Plugin) obj;
// ^ ClassCastException if Plugin was loaded by the app loader
//   but obj was loaded by loader1

// Check which loader loaded a class
System.out.println(String.class.getClassLoader());         // null (Bootstrap)
System.out.println(ArrayList.class.getClassLoader());      // null (Bootstrap)
System.out.println(MyService.class.getClassLoader());      // AppClassLoader

Custom ClassLoader for Hot Reload

Hot reload works by creating a new ClassLoader that loads the updated class bytecode, discarding the old loader. When no references to the old loader or its classes remain, the GC can collect the old classes (class unloading).

Spring DevTools, JRebel, and OSGi all use this mechanism. The key: the new loader must NOT delegate to the parent for the classes you want to reload — it breaks the delegation model intentionally.

HotReload.java
public class HotReloadClassLoader extends URLClassLoader {
    private final Set<String> reloadablePackages;

    public HotReloadClassLoader(URL[] urls, ClassLoader parent,
            Set<String> reloadablePackages) {
        super(urls, parent);
        this.reloadablePackages = reloadablePackages;
    }

    @Override
    protected Class<?> loadClass(String name, boolean resolve)
            throws ClassNotFoundException {
        // Break delegation for reloadable classes
        if (isReloadable(name)) {
            synchronized (getClassLoadingLock(name)) {
                Class<?> c = findLoadedClass(name);
                if (c == null) c = findClass(name); // load fresh
                if (resolve) resolveClass(c);
                return c;
            }
        }
        return super.loadClass(name, resolve); // delegate for rest
    }

    private boolean isReloadable(String name) {
        return reloadablePackages.stream().anyMatch(name::startsWith);
    }
}

// Hot reload: replace the loader and re-instantiate
void reload() throws Exception {
    if (currentLoader != null) currentLoader.close(); // allow GC
    currentLoader = new HotReloadClassLoader(urls, parent, pkgs);
    Class<?> fresh = currentLoader.loadClass("com.example.App");
    app = fresh.getDeclaredConstructor().newInstance();
}

Class Unloading and Metaspace

A class can be unloaded when its ClassLoader is GC'd. For the loader to be GC'd, there must be no live references to the loader itself or to any class/object it loaded.

Metaspace grows until MaxMetaspaceSize is hit. In systems that generate many classes (proxies, lambdas serialised as classes, dynamic code generation), Metaspace can fill up. Monitor with -verbose:class or JFR class loading events.

ClassUnloading.java
// Force class unloading by releasing all references
WeakReference<ClassLoader> loaderRef =
    new WeakReference<>(currentLoader);

// Release all strong references
currentLoader = null;
allLoadedInstances.clear(); // clear any objects from that loader

// Suggest GC (not guaranteed)
System.gc();

// If loaderRef.get() == null → loader was GC'd → classes unloaded

// Metaspace monitoring
// -verbose:class                  — log class load/unload
// -XX:MaxMetaspaceSize=512m       — cap Metaspace
// -XX:+CMSClassUnloadingEnabled   — enable class unloading (old GC)

// JFR event: jdk.ClassLoad, jdk.ClassUnload

// Dynamic proxy — each creates a new class loaded into Metaspace
Object proxy = Proxy.newProxyInstance(
    cls.getClassLoader(),
    new Class<?>[]{ MyInterface.class },
    (p, method, args) -> method.invoke(target, args));
// Generating thousands of proxies can fill Metaspace

Interactive Visualization

Class Loading
ClassLoader
Bootstrap CL
Platform CL
App CL
Method Area
Class metadata
Static fields
Constant pool
Heap
Young Gen (Eden)
Old Gen
Objects
JVM Stack
main() frame
Local vars
Operand stack
PC Register
Instruction ptr
JVM starts: ClassLoader loads .class bytecode into the Method Area.
1 / 6

Key Points to Remember

  • Class identity = fully-qualified name + ClassLoader — same name, different loaders = different types.
  • Parent delegation prevents classpath classes from overriding Bootstrap classes (java.lang.*).
  • Hot reload: break parent delegation for target classes, create a new loader, discard the old.
  • Class unloading: happens when loader is GC'd — requires no live references to loader or its classes.
  • Metaspace leaks: typically caused by class loader leaks (dynamic proxies, runtime code generation).

Practice Class Loading and Hot Reload in the Playground

Run and modify code directly in your browser - no setup needed.

Interview Questions

Sign in to ask Aria
1

What is the parent delegation model and why does it exist?

MediumOracle
2

Why can two objects of the "same" class throw ClassCastException?

HardGoogle
3

How does hot reload work with ClassLoaders?

HardAmazon
4

What causes Metaspace to grow indefinitely?

HardNetflix
5

What must be true for a class to be unloaded by the JVM?

HardMicrosoft

Ask Aria about Class Loading and Hot Reload

Your personal AI tutor — ask anything about this concept