jstat 是查看 java 进程实时堆内存使用率的最快最准工具,不触发 gc、不挂起进程;推荐用 jstat -gc -t 1s 关注 eu、ou 及 ou/oc 比值(超 70% 需警惕),注意 jdk 版本字段差异。

怎么看 Java 进程当前堆内存用了多少——jstat 最快最准
直接看实时堆使用率,jstat 是首选。它不触发 GC、不挂起进程、输出轻量,适合线上快速排查。
常见错误是用 jmap -heap 查“当前”用量,其实它只显示 GC 后的统计快照,且会暂停应用几秒,高负载下可能引发超时雪崩。
-
jstat -gc <pid></pid>每秒刷新一次,重点关注EU(Eden 使用)、OU(Old 使用)、OU/OC比值——这个比值超过 70% 就得警惕老年代快满了 - 加
-t参数能显示时间戳,方便和监控图表对齐:jstat -gc -t 12345 1s - 注意 JDK 版本差异:JDK 8 默认用 Parallel GC,
jstat输出字段名是PU/GU;JDK 17+ 用 G1,默认字段变成G1E/G1O,别硬套旧文档的列名
想导出完整的堆对象分布——jmap -histo 别带 -F
查哪些类占内存最多,jmap -histo 足够,但加 -F(强制 dump)风险很大:它会尝试 attach 到卡死的 JVM,可能让进程彻底无响应。
使用场景很明确:GC 频繁但 OU 没涨?说明对象生命周期短,重点看 jstat 的 YGC 次数和耗时;OU 持续上涨?再用 jmap -histo 找大头。
立即学习“Java免费学习笔记(深入)”;
-
jmap -histo 12345 | head -20快速看前 20 名,关注[B(byte[])、java.util.HashMap、自定义缓存类 - 如果进程响应慢但没卡死,去掉
-F;加上反而容易失败,报错sun.jvm.hotspot.debugger.DebuggerException: Can't attach to the process - 输出里
bytes列是估算大小,不是真实 Shallow Heap,不能直接等同于 OOM 原因,只是第一层线索
jmap -dump 生成堆转储后,别用记事本打开
生成的 .hprof 文件动辄几百 MB,记事本或 VS Code 直接打不开,强行加载会假死。必须用专业分析工具读取。
性能影响很实际:执行 jmap -dump:format=b,file=heap.hprof 12345 期间,JVM 会 STW(全局停顿),时长取决于堆大小和 GC 状态。一个 4G 堆可能卡住 3–8 秒。
- 线上慎用,优先在低峰期操作;若必须紧急 dump,先用
jstat确认老年代确实持续增长,避免误判 - 生成后立刻压缩:
gzip heap.hprof,减小传输和存储压力 - 分析用
Eclipse MAT或JProfiler,导入时选 “Leak Suspects Report”,比手动翻 dominator tree 快得多
为什么 jmap -heap 显示的 MaxHeapSize 和启动参数对不上
这是 JDK 内部计算逻辑导致的,不是配置写错了。JVM 启动时会按比例预留元空间、CodeCache、线程栈等内存,真正留给堆的 MaxHeapSize 会被向下取整到页对齐边界(通常是 2MB 或更大)。
比如你加了 -Xmx4g,jmap -heap 却显示 MaxHeapSize = 4261412864(约 3.97G),差那几十 MB 就是页对齐损耗。
- 检查是否真被限制,看
jstat -gc的MC(Metacapacity)和CCSC(Compressed Class Space Capacity),它们和堆抢内存 - 容器环境更明显:Docker 里没配
-XX:+UseContainerSupport,JVM 可能按宿主机内存算 MaxHeap,导致jmap -heap和docker stats对不上 - 别依赖
jmap -heap做容量规划,以jstat实时指标 + GC 日志里的max字段为准
堆内存不是静态水位表,它是动态博弈的结果——GC 策略、对象年龄、元空间膨胀、甚至 Linux 的 overcommit 设置都会悄悄改写你看到的数字。盯住 jstat 的流式输出,比截一张 jmap 快照有用得多。










