jstat -class 是最轻量、贴近生产环境的类加载监控方式,通过 loaded、bytes、unloaded 指标可识别类泄漏;结合 jstat -gccause 和 gc 日志验证元空间回收异常;定位需排查 classloader 引用链及热部署工具影响。

直接用 jstat -class 就能实时观察类加载行为,这是最轻量、最贴近生产环境的监控方式。它不依赖 JMX,也不需要改启动参数,只要拿到 Java 进程 PID 就能运行。
用 jstat -class 抓关键指标
执行 jstat -class <pid><interval></interval></pid>(例如每 2 秒刷新一次):
- loaded:当前已加载类总数 —— 持续上涨且无回落,是类泄漏的第一信号
- bytes:加载类占用字节数 —— 粗略对应元空间(Metaspace)使用量
- unloaded:已卸载类数量 —— 长期为 0 或极低,说明类几乎不卸载,需警惕自定义 ClassLoader 持有引用
结合 -gccause 和 GC 日志交叉验证
类加载异常常触发元空间回收,进而引发 Full GC。可同步运行:
-
jstat -gccause <pid> 1000</pid>:看每次 GC 是否由 Metadata GC Threshold 触发 - 检查 GC 日志中是否频繁出现
Metaspace相关回收记录,尤其是Full GC (Metadata GC Threshold) - 若 loaded 持续增长 + FGC 频繁 + Metaspace 使用率单边上升 → 基本锁定类加载泄漏
定位泄漏源头的实操线索
类无法卸载的根本原因在于类加载器未被回收。重点关注:
- 是否使用了热部署工具(Spring Boot DevTools、JRebel)或 OSGi 容器
- 是否存在 ThreadLocal 持有 ClassLoader 实例(常见于 Web 容器线程池复用场景)
- 自定义 ClassLoader 是否被静态变量、缓存、监听器等长期强引用
- JDK 版本差异:JDK 9+ 平台类加载器不再可卸载,只有自定义加载器加载的类才可能释放
辅助验证与深度排查
单靠 jstat 不足以定位具体哪个类泄漏,需配合其他手段:
-
jcmd <pid> VM.native_memory summary</pid>:确认元空间内存是否真实增长 -
jmap -clstats <pid></pid>(慎用,会 STW):列出各 ClassLoader 加载的类数,识别异常加载器 - 开启详细类加载日志:
-XX:+TraceClassLoading -XX:+TraceClassUnloading(仅限测试环境) - 用 VisualVM 或 JProfiler 的“ClassLoader”视图,直观查看加载器树和实例引用链











