可用jcmd或jmap命令动态分析jvm堆内存占用,jcmd gc.class_histogram -all仅统计存活对象且无停顿,jmap -histo:live触发gc后统计更准确;结合grep、awk脚本聚焦业务类,再用jstat -gc观察老年代增长与gc频率判断泄漏。
直接用 jvm 自带命令就能动态分析当前进程里哪些堆对象占内存最多,不需要导出 dump 文件,也不依赖图形工具。关键在于用对命令、加对参数、看懂输出。
用 jcmd 快速获取存活对象直方图
jcmd 是 JDK 8u60+ 推荐的轻量级替代方案,比 jmap 更低开销,不触发全局停顿。
- 执行 jcmd
GC.class_histogram :获取当前堆中所有类的实例数和总大小(含已回收对象) - 执行 jcmd
GC.class_histogram -all :只统计存活对象,结果更贴近真实压力点 - 输出前三列分别是:序号、类名、实例数量、字节总数。按字节排序可定位大对象,按数量排序可发现集合类滥用
用 jmap -histo 实时抓取并排序
如果环境是 JDK 7 或早期 JDK 8,jmap -histo 仍是主力。注意加 live 参数避免干扰:
-
jmap -histo:live
:强制先做一次 minor + full GC,再统计存活对象——结果干净但有短暂停顿 -
jmap -histo
| sort -k3 -nr | head -20 :按字节占用倒序排,快速看到前 20 名“内存大户” - 重点关注类名含 ArrayList、HashMap、byte[]、String、业务 VO/DTO 类(如 OrderVO、UserCache)的行
写个一键分析脚本定位业务对象
把常用筛选逻辑固化成脚本,避免每次手动 grep 和 sort:
- 脚本中加入 grep -E "com\.yourcompany|Order|Cache|DataObject",聚焦业务核心类
- 用 awk '{printf "%-8s %12s %12s %s\n", $2, $3, $4, $5}' 对齐输出,便于肉眼扫读
- 配合 watch -n 5 './heap-histo.sh
' 每 5 秒刷新一次,观察对象增长趋势
结合 jstat 看对象生命周期是否异常
单看占比不够,要判断这些对象是不是该活这么久:
- 运行 jstat -gc
2000 (每 2 秒刷新),观察 OU(老年代已用) 是否持续上涨 - 如果 OU 增长快,而 jmap -histo:live 显示大量业务对象在 old 区,说明可能有缓存未清理、监听器未注销、线程局部变量泄漏
- 对比 YGC 频率 和 FGC 频率:若 YGC 很多但对象仍进老年代,大概率是 -XX:PretenureSizeThreshold 设置不当或大数组直接分配











