类卸载需同时满足三条件:所有实例被回收、类加载器不可达、Class对象无任何引用;双亲委派使系统类永驻,自定义类加载器若被意外引用则导致元空间泄漏。
Java 类加载器与垃圾回收看似独立,实则存在隐性但关键的耦合关系——类加载器影响对象生命周期起点,而垃圾回收机制决定其终点;更深层地,类本身能否被卸载,直接取决于垃圾回收是否已清理掉所有对该类及其类加载器的引用。
类加载器负责将 .class 字节码加载进方法区(JDK 8+ 为元空间),并生成对应的 java.lang.Class 实例。这个 Class 对象本身是堆中普通对象,由 GC 管理。只有当满足以下全部条件时,JVM 才可能卸载该类:
三者缺一不可。其中第二条尤为关键:类加载器若仍存活,它所加载的所有类都无法被卸载,哪怕这些类早已不再使用。
Bootstrap、Extension、Application 类加载器均由 JVM 内部持有强引用,生命周期与 JVM 一致。它们加载的类(如 java.lang.Object、java.util.ArrayList)因此始终有活跃引用链,不可能被 GC 判定为“不可达”,自然也不会触发卸载逻辑。这种设计不是 GC 的限制,而是类加载器架构对 GC 行为的约束。
立即学习“Java免费学习笔记(深入)”;
在热部署、插件化、OSGi 等场景中,开发者常创建临时类加载器加载业务模块。此时,模块卸载成功与否,完全依赖 GC 是否能回收该类加载器:
这类问题通常表现为元空间持续增长、Full GC 频繁却无法释放,根源不在对象本身,而在类加载器引用未断。
启用 -XX:+TraceClassUnloading 可在 GC 日志中看到“Unloading class xxx”记录,表明类卸载成功;配合 jcmd <pid> VM.native_memory summary 或 jstat -gcmetacapacity <pid> 观察元空间使用趋势,能判断类加载器是否真正释放。注意:卸载是异步且非强制的,JVM 只在合适时机执行,不会因类无用就立刻卸载。