JVM中的引用链、类加载器泄漏

堆中的每个对象都是一个链条的开端

以堆中的一个对象person1为视角:
person1 实例 (堆) ➔ InstanceKlass (元空间) ➔ Person.class (堆) ➔ ClassLoader (堆) ➔ 全部 Class 镜像 (堆) ➔ 全部类元数据 (元空间)。
堆中的对象实例 person1 通过对象头里的类型指针classPointer先指向元空间底层的 InstanceKlass C++结构体🏛️,
➡️ 接着由其内部的 _java_mirror 指针
反指回
堆中的 Person.class 镜像对象 🪞,
➡️ 该 Class 对象再通过内部变量强引用同在堆中的 ClassLoader 实例 🔗,
➡️ 最后,ClassLoader 通过其 classes 集合兜底强引用了它加载过的所有堆内 Class 对象 📦,
➡️ 而这些对象又各自死死绑定着元空间里庞大的所有类元数据 🧠,
最终形成了一条牵一发而动全身的跨区死亡链条。

什么是类加载泄漏?

指的是一个原本应该被销毁的自定义类加载器(以及它在元空间中加载的所有类元数据),
因为其加载的某个类或对象实例被外部长生命周期的对象(如系统级线程)强引用,导致整个类加载器及其背后的庞大元数据群无法被垃圾回收,
最终撑爆元空间(触发 java.lang.OutOfMemoryError: Metaspace)。

生产案例

结合 Tomcat 内存泄漏案例,把强引用链一环环画出。这条完整的跨区域链路如下:

Tomcat 核心线程 (GC Root)
⬇️ (强引用)
ThreadLocalMap
⬇️ (强引用)
person1 实例 (堆)
⬇️ (Klass Pointer 类型指针)
Person 的 InstanceKlass (元空间)
⬇️ (_java_mirror 镜像指针)
Person.class 对象 (堆)
⬇️ (classLoader 成员变量)
WebappClassLoader 实例 (堆)
⬇️ (classes Vector 集合)
成千上万个其他的 Class 对象 (堆)
⬇️ (隐藏的底层指针)
成千上万个其他的 InstanceKlass (元空间)

只要最上层的 person1 没被释放,顺着这条跨越 “堆 -> 元空间 -> 堆 -> 堆 -> 堆 -> 元空间” 的九转大肠般的链路,整套业务代码的元数据就永远被“锁死”在内存里,最终导致 OOM。

posted @ 2026-03-12 16:40  Nickey103  阅读(21)  评论(0)    收藏  举报