Java不支持主动类卸载,仅当自定义ClassLoader被GC回收且无引用时自动卸载;需隔离加载器、避免强引用,并可用-XX:+TraceClassUnloading验证。

Java 本身不支持真正意义上的“类卸载”,但可以在运行时动态加载类;卸载仅在特定条件下由 JVM 自动完成(如类加载器被回收、无任何引用),无法主动触发。关键在于合理使用自定义 ClassLoader,配合类生命周期管理策略。
动态加载类:用自定义 ClassLoader 加载字节码
标准 Class.forName() 或 ClassLoader.getSystemClassLoader().loadClass() 使用的是系统类加载器,无法隔离和后续清理。正确做法是:
- 继承
ClassLoader,重写findClass(String name)方法,从文件、JAR、网络等来源读取字节码(byte[]) - 调用
defineClass(name, bytes, 0, bytes.length)将字节码转为Class对象 - 确保该 ClassLoader 没有强引用到加载的类或其实例,否则 GC 无法回收它
示例片段:
public class DynamicClassLoader extends ClassLoader {
private final Map<String, byte[]> classBytes = new HashMap<>();
public void defineClass(String name, byte[] bytes) {
classBytes.put(name, bytes);
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
byte[] bytes = classBytes.get(name);
if (bytes == null) throw new ClassNotFoundException(name);
return defineClass(name, bytes, 0, bytes.length);
}
}
// 使用
DynamicClassLoader loader = new DynamicClassLoader();
loader.defineClass("com.example.Hello", bytecode);
Class<?> clazz = loader.loadClass("com.example.Hello");
Object instance = clazz.getDeclaredConstructor().newInstance();
实现“可卸载”的前提:隔离类加载器 + 及时释放引用
类能否被卸载,取决于其 所属 ClassLoader 是否能被 GC 回收。因此必须做到:
立即学习“Java免费学习笔记(深入)”;
- 每个动态类使用独立的 ClassLoader 实例(不要复用)
- 不将动态类的 Class 对象、实例、静态字段、线程上下文类加载器(
Thread.setContextClassLoader())等长期持有 - 显式将 loader 引用置为
null,并确保无其他隐式引用(如监听器、缓存、日志框架绑定) - 避免在动态类中引用系统类加载器加载的类(尤其不要传递
this.getClass().getClassLoader()给全局服务)
验证类是否被卸载:借助 JVM 参数与工具
卸载不可编程控制,但可观察是否发生:
- 启动参数添加
-XX:+TraceClassUnloading,运行时查看日志中是否有Unloading class com.example.Hello - 用
jstat -class <pid></pid>观察 loaded / unloaded 类数量变化 - 结合
jmap -histo:live <pid></pid>或 VisualVM 查看 ClassLoader 实例是否已被回收
注意:只有在 Full GC 后,且该 ClassLoader 确实无任何可达引用时,其加载的所有类才可能被卸载。
替代思路:热替换更推荐用 Java Agent 或 JDI
若目标是开发期热更新(如修改方法体),不建议自己实现加载/卸载,而应使用:
- Java Agent + Instrumentation.redefineClasses():可替换已有类的字节码(要求方法签名不变,不新增字段)
- JDI(Java Debug Interface):通过调试协议实现更灵活的重定义(IDE 如 IntelliJ 的 “HotSwap” 即基于此)
- 成熟框架如 Spring Loaded(已归档)、JRebel(商业)或 HotswapAgent(开源)
这些方案绕开了类卸载限制,在限定场景下更稳定可靠。


















