jstat用于实时监控Java进程内存与GC状态,轻量非侵入;jmap可生成堆快照或打印对象统计,适合深入分析变量分布与内存泄漏。

要查看 Java 进程运行时的内存变量状态,jmap 和 jstat 是 JDK 自带的两个关键诊断工具:jstat 用于实时监控内存和 GC 活动,轻量、非侵入;jmap 则可生成堆快照(heap dump)或打印对象统计,适合深入分析变量分布与内存泄漏线索。
用 jstat 实时观察内存与 GC 状态
jstat 命令不暂停应用,适合生产环境周期性采样。常用模式是监控堆各区域使用率和 GC 频次:
-
查看类加载、JIT 编译、GC 概览(每 1 秒刷新 5 次):
jstat -gc -h5 <pid> 1000 5</pid>
输出中重点关注S0U/S1U(幸存区使用)、EU(伊甸园区)、OU(老年代)、MU(元空间),以及YGCT/FGCT(年轻代/全 GC 耗时) -
聚焦元空间与类加载趋势(防 Metaspace OOM):
jstat -class <pid></pid>查看已加载类数、字节数及卸载量;jstat -gccapacity <pid></pid>查看各代容量上限 -
发现异常信号:若
OU持续增长且FGCT频繁上升,可能有大对象长期驻留或内存泄漏;若EU长期接近 100% 但YGCT很低,可能是 Eden 区设置过大或应用无实际对象创建
用 jmap 抓取堆中活跃对象与变量分布
jmap 可在不终止进程前提下导出堆快照或打印实例统计,定位“哪些类占内存多”、“某类有多少实例”:
-
列出堆中所有类的实例数量与占用大小(按大小倒序):
jmap -histo:live <pid> | head -20</pid>
注意加:live触发一次 Minor GC 再统计,结果更准确;重点关注char[]、byte[]、String、自定义 VO/DTO 类等高频内存消耗者 -
导出二进制堆快照供可视化分析(如用 Eclipse MAT 或 VisualVM):
jmap -dump:format=b,file=heap.hprof <pid></pid>
建议在业务低峰执行,避免 I/O 影响;若进程响应慢,可加-F强制(需 root 权限,Linux 下可能触发 safepoint) -
检查运行时常量池与系统属性(辅助排查 ClassLoader 泄漏):
jmap -permstat <pid></pid>(JDK 7 及以前)或jmap -clstats <pid></pid>(JDK 8+)查看各 ClassLoader 加载的类数与存活对象引用关系
组合使用技巧:从监控到定位
单靠一个命令难闭环。典型实战路径是:先 jstat 发现 OU 持续上涨 → 再 jmap -histo 找大头类 → 若怀疑泄漏,jmap dump 后用 MAT 查 dominator tree 和 leak suspect 报告:
- 例如 jstat 显示
OU从 200MB 升至 800MB 且不回落,jmap -histo:live显示java.util.HashMap$Node实例超 200 万 —— 可能是缓存未清理或监听器注册后未注销 - 若 jmap dump 后 MAT 中看到大量
org.springframework.context.support.LiveBeansView引用链,说明 Spring Boot Actuator 的 /actuator/beans 接口被频繁调用并缓存了 Bean 元信息(真实案例) - 注意权限与时机:普通用户只能 attach 自己启动的 Java 进程;容器中需确保 jdk 工具包存在且 PID 可见(如 Docker 启动时加
--cap-add=SYS_PTRACE)
注意事项与常见问题
这两个工具看似简单,但易踩坑:
-
jmap -dump 在高负载时可能卡住进程数秒甚至分钟,线上慎用;优先尝试
jmap -histo:live或结合 JVM 参数-XX:+HeapDumpOnOutOfMemoryError预埋机制 - jstat 输出列名随 JDK 版本略有差异(如 JDK 8 的
OU在 JDK 11+ 变为OU仍可用,但MU替代了旧版PU),建议用jstat -options查看当前支持选项 - 容器环境常因 PID 命名空间隔离导致
jps不可见目标进程,改用ps aux | grep java并确认容器内 PID;必要时将 jdk/bin 挂载进容器临时调试


















