jstat -gcutil 是诊断 Java 内存问题最轻量、最常用的实时命令之一,通过监控 O(老年代使用率)、M(元空间使用率)、Y(Young GC 次数)的组合变化趋势,可快速定位老年代泄漏、元空间泄漏或新生代对象逃逸等典型内存问题。

jstat -gcutil 是诊断 Java 内存问题最轻量、最常用的实时命令之一。它不依赖堆转储,也不需重启应用,适合线上快速筛查。关键在于读懂 O(老年代使用率)、M(元空间使用率)、Y(Young GC 次数) 这三个指标的组合变化趋势——它们各自波动本身不说明问题,但同步持续上升或异常滞高,往往能精准指向泄漏发生的内存区域。
O 值持续攀升且不回落 → 老年代存在对象堆积或泄漏
老年代(Old Generation)本应只存放长期存活对象。若 O(即 OU / OC 的百分比)在多次 jstat -gcutil <pid> 2000</pid> 采样中单向上涨、无明显回落(例如从 45% → 62% → 79% → 95%),尤其伴随 FGC 次数增加但 OU 降得极少(如 Full GC 后只从 95% 降到 92%),说明:
- 新生代晋升的对象越来越多,且老年代无法有效回收
- 很可能有长生命周期对象(如静态缓存、未关闭的监听器、线程局部变量 TLV 泄漏)持续持有引用
- 若
OC(老年代容量)固定,而OU持续逼近 100%,OOM in old gen 几乎是时间问题
✅ 建议动作:立即用
jmap -histo:live <pid></pid>查看前 20 名对象实例数;重点关注HashMap$Node、ArrayList、自定义 DTO 或 Service 类的实例是否异常膨胀。
M 值缓慢但稳定上升,且不随 Full GC 下降 → 元空间泄漏(常见于类加载器未卸载)
M 表示元空间(Metaspace)使用率(MU / MC)。JDK 8+ 中,类元数据不再放在永久代,而是本地内存中的元空间。它的特点是:
不受堆 GC 影响,Full GC 不清理元空间
正常应用中
M会在启动后快速升至某平台期(类加载完成),之后基本持平-
若
M随时间缓慢但不可逆地上升(如每小时 +0.5%,一天后从 30% → 65%),且MC(最大元空间容量)未被显式限制(即没配-XX:MaxMetaspaceSize),极可能是:- 动态生成类(如 Spring AOP 代理、Groovy 脚本、Javassist/CGLIB 大量创建代理类)
- Web 应用热部署未清理旧 ClassLoader,导致已加载类无法卸载(
java.lang.ClassLoader实例持续增多) - 使用了
Instrumentation.redefineClasses但未配合类卸载逻辑
✅ 建议动作:执行
jstat -class <pid></pid>观察loaded类总数是否持续增长;再用jmap -clstats <pid></pid>检查各 ClassLoader 加载类数及存活状态。
Y 值高频触发,但每次 YGC 回收效果变差(E 区下降少、S0/S1 复制失败多)→ 新生代对象“逃逸”加剧,间接暴露老年代压力
Y 是 Young GC 次数。单独看 Y 高并不异常(高并发小对象场景本就频繁 Minor GC)。真正危险信号是:
-
Y频率升高(如从 1 次/10s 变成 1 次/2s) - 同时
E(Eden 使用率)每次 GC 后下降幅度越来越小(如原来从 98% → 15%,现在只到 65%) -
S0U/S1U在 GC 后明显上升,甚至出现S0U > S0C(Survivor 区溢出),触发提前晋升
这说明:大量对象在 Eden 区“活过一轮 GC”,被复制到 Survivor,又因 Survivor 空间不足或年龄阈值低,被迫直接晋升到老年代——本质是新生代对象生命周期被意外拉长,背后常是:
- 方法内创建了本该复用的临时集合(如每次请求 new HashMap() 且被闭包捕获)
- Lambda 表达式隐式持有了外部大对象引用
- 日志框架(如 Logback)配置不当,导致 MDC 中塞入了大对象或未清理的上下文
✅ 建议动作:开启
-XX:+PrintGCDetails -XX:+PrintGCTimeStamps,观察日志中[GC (Allocation Failure) ... DefNew: xxxK->yyyK(...)]的->yyyK是否逐次增大;配合jstack抓线程快照,比对高分配线程的调用栈。
综合来看,三者不是孤立指标:
-
O↑ + FGC↑ + Y↑→ 典型堆内泄漏,聚焦业务缓存与静态集合 -
M↑ + loaded↑ + Y基本稳定 → 元空间泄漏,检查类加载器和动态字节码 -
Y↑ + E↓ 少 + S0U↑→ 新生代“失守”,泄漏源头可能在代码写法或框架使用姿势
不需要等 OOM,只要连续 5~10 分钟观察到上述任一模式,就该介入排查。


















