JVM Internalscritical

ClassLoader Hierarchy

ClassLoaders load .class files into the JVM on demand. There are three built-in loaders: Bootstrap (loads rt.jar / core JDK classes), Platform/Extension, and Application (loads classpath classes). They form a parent-delegation hierarchy.

Memory anchor

ClassLoader = bouncer chain at a nightclub. Each bouncer asks the bouncer above them first: 'Do you know this person?' Only if no parent recognizes you does the local bouncer check the list.

Expected depth

The parent-delegation model means a ClassLoader always asks its parent first before loading a class itself, preventing user code from shadowing core JDK classes. Classes are identified by (ClassLoader, fully-qualified name) pairs — the same class loaded by two different ClassLoaders are distinct types and will fail instanceof checks. Custom ClassLoaders are used in OSGi, application servers, and hot-reload frameworks (Spring DevTools).

Deep — senior internals

Each ClassLoader maintains its own namespace. Class unloading only happens when a ClassLoader becomes unreachable — important for preventing PermGen/Metaspace leaks in app servers that deploy/undeploy apps repeatedly. The ClassLoader that loaded a class is its 'defining loader'; others that delegated to it are 'initiating loaders'. Security managers use ClassLoader identity to enforce sandbox boundaries. GraalVM's native-image performs closed-world analysis at build time, effectively collapsing this runtime hierarchy.

🎤Interview-ready answer

The JVM uses a parent-delegation model: each ClassLoader delegates to its parent before trying to load a class itself, ensuring core JDK classes cannot be overridden by user code. Classes are uniquely identified by their name plus the ClassLoader that defined them — the same .class file loaded by two different ClassLoaders produces two incompatible types. This is why application servers isolate each deployed app with its own ClassLoader and why ClassLoader leaks cause Metaspace OOMs when classes can't be unloaded.

Common trap

Two classes with the same fully-qualified name loaded by different ClassLoaders are NOT the same type — casting between them throws ClassCastException even though the bytecode is identical.