类加载器动态卸载不依赖zgc或g1主动并发卸载,而是由jvm在gc标记阶段配合可达性分析判定classloader及class是否可回收,再由元空间管理器触发清理;gc仅确认引用断开,不直接执行卸载。

类加载器的动态卸载在ZGC和G1中**不依赖GC算法本身主动“并发卸载”类**,而是由JVM在特定GC阶段配合可达性分析,判断类加载器及其Class对象是否可回收——卸载动作发生在元空间(Metaspace)清理环节,不是GC线程直接执行“卸载类”,而是GC协助打破强引用循环后,由元空间管理器触发清理。
类卸载的前提与GC的角色
类能否被卸载,根本取决于三个条件是否同时满足:所有实例已回收、类加载器实例无外部强引用、对应的Class对象无强引用。GC(无论G1还是ZGC)的作用是:确认这些引用是否真正断开。它不“主动卸载类”,但通过并发标记或SATB快照,精准识别出哪些Class对象和类加载器已不可达。
- G1在并发标记阶段使用SATB(Snapshot-At-The-Beginning)机制,记录标记开始时的对象图快照;重新标记阶段修正变动,最终确定Class对象及类加载器是否存活
- ZGC在并发标记阶段采用染色指针+读屏障,能实时捕获对象引用关系变化,对Class对象和ClassLoader的可达性判定更细粒度、更及时
- 两类GC都**不单独设计“类卸载线程”**,而是在Full GC或元空间触发清理时,复用已有的并发标记结果驱动卸载
G1中的类卸载实现路径
G1自JDK 9起默认启用类卸载(-XX:+ClassUnloading,默认开启),但仅在Mixed GC或Full GC中生效。它不保证每次GC都卸载类,而是当元空间使用率超过阈值(-XX:MetaspaceSize)或发生元空间分配失败时,触发元空间清理流程:
- 先完成老年代+新生代的Mixed GC(若适用),同时完成全堆并发标记
- 标记结束后,扫描元空间中所有Klass结构,结合GC的存活对象图,判断对应ClassLoader是否已不可达
- 若ClassLoader不可达,则其加载的所有Class元数据被批量释放,元空间内存归还
- 注意:G1的类卸载仍伴随STW阶段(如重新标记、清除元空间空闲块),并非全程完全并发
ZGC中的类卸载特点
ZGC的设计目标是亚毫秒级停顿,因此对类卸载做了更激进的解耦:
- 类卸载逻辑从GC主循环中进一步剥离,由独立的元空间后台线程(MetaspaceGC thread)异步执行
- ZGC的并发标记结果(基于染色指针)直接提供给元空间管理器,无需额外STW来确认ClassLoader存活状态
- 只要GC标记确认ClassLoader不可达,元空间即可在下一个安全点之后立即启动卸载,延迟更低、更平滑
- 但ZGC仍需在卸载前确保:所有对该ClassLoader或Class的反射调用已完成,且无JNI全局引用持有Class对象(这部分由JVM运行时保障,非GC负责)
实际调优与验证建议
想让类卸载真正生效,光靠换GC还不够,关键在应用侧控制类加载器生命周期:
- 避免将自定义ClassLoader存入静态字段或ThreadLocal长期持有——这是最常见的泄漏根源
- 使用
jstat -gc <pid></pid>观察MU(Metaspace Used)和MC(Metaspace Capacity)变化,持续增长说明卸载未发生 - 开启
-XX:+PrintGCDetails -XX:+PrintGCTimeStamps,查找日志中类似“Unloading class xxx”或“Metaspace garbage collection”的提示 - ZGC下可额外加
-XX:+UnlockExperimentalVMOptions -XX:+UseZGCStrictMemoryOrdering提升元空间清理确定性(JDK 21+)











