核心工具对比:jmap vs jcmd
| 特性 | jmap (传统工具) |
jcmd (新一代全能工具) |
|---|---|---|
| 定位 | Java内存映射工具,功能专一。 | JVM诊断命令工具,功能强大且统一。 |
| 主要功能 | 生成堆转储、打印类直方图等。 | 几乎涵盖所有诊断操作:堆转储、GC、线程、类、JFR等。 |
| 安全性 | 某些操作可能强制Full GC,对线上系统有风险。 | 操作通常更安全、侵入性更小。 |
| 推荐度 | 逐渐被 jcmd 取代,仅在旧脚本或特定场景使用。 |
强烈推荐,是JDK自带工具集的首选。 |
结论:优先学习和使用 jcmd。
详解 jcmd:查询与分析堆内存
jcmd 是一个向正在运行的Java进程发送诊断命令请求的工具。其基本语法为:
bash
jcmd <pid> <command> [arguments]
第一步:找到你要诊断的Java进程PID
bash
jcmd -l
# 或
jps -mlv
这会列出所有Java进程及其主类和进程ID。
第二步:使用 jcmd 执行关键内存诊断命令
假设目标进程的PID是 12345。
1. 打印堆内存摘要(最快速概览)
bash
jcmd 12345 GC.heap_info
输出示例与解读:
PS Young Generation
eden space: ... capacity, used ...
from space: ...
to space: ...
PS Old Generation
capacity, used...
这让你快速看到**新生代(Young Gen)和老年代(Old Gen)**的容量和使用情况,是判断内存压力的第一手信息。
2. 生成堆转储文件(用于深度分析内存泄漏)
这是最核心、最常用的功能。
bash
jcmd 12345 GC.heap_dump -all=true /path/to/save/heapdump.hprof
-all=true:包含所有对象,包括不可达的(有利于分析),文件会更大。- 文件通常以
.hprof为后缀。 - 应用场景 :当应用出现
OutOfMemoryError或内存使用率持续攀升时,生成堆转储,然后用可视化工具分析。
3. 查看类直方图(了解哪些类占用了最多内存)
bash
jcmd 12345 GC.class_histogram
输出示例:
num #instances #bytes class name
----------------------------------------------
1: 1000000 1000000000 [B // 字节数组
2: 500000 200000000 java.lang.String
3: 10000 80000000 com.example.MyBigObject
- 按实例的总占用内存排序。
[B代表byte[],[C代表char[],它们和String通常排在前列是正常的。但如果你的业务对象(如MyBigObject)异常靠前且数量不合理,就可能是泄漏点。
4. 触发垃圾回收(谨慎使用)
bash
jcmd 12345 GC.run
注意 :这只是一个"建议"JVM进行Full GC的请求,JVM不保证立即执行。不要频繁执行,以免影响性能。
实战应用场景与步骤
场景:线上Web应用响应变慢,监控显示老年代内存使用率超过80%且持续增长,怀疑有内存泄漏。
排查步骤:
-
定位进程:
bashssh 线上服务器 jcmd -l | grep 你的应用名 # 输出:12345 com.example.MainApp -
快速检查:
bashjcmd 12345 GC.heap_info确认老年代使用率确实很高,且回收后下降不明显。
-
生成关键时刻的堆转储:
bashjcmd 12345 GC.heap_dump /tmp/heapdump_`date +%Y%m%d_%H%M%S`.hprof最佳实践:在内存使用率高位和低位(如重启后)各生成一份,对比分析效果更佳。
-
下载
.hprof文件到本地,使用专业工具分析。
如何分析堆转储文件?
生成 .hprof 文件后,需要用图形化工具分析:
-
Eclipse MAT
- 最强大、最常用的堆转储分析工具。
- 核心功能 :
- Leak Suspects Report:自动生成泄漏可疑点报告。
- Histogram:类直方图,可计算"支配树"。
- Dominator Tree:支配树,直接找到持有最大内存的对象。
- 实战 :在支配树中,如果发现某个业务类的成千上万个实例被同一个
ThreadLocal或某个静态Map引用,那就是典型的泄漏。
-
VisualVM
- JDK自带,简单直观。
- 适合快速浏览对象数量、执行OQL查询。
分析思路 :在MAT中,对比两个时间点的堆转储,重点关注** retained heap(支配内存)增长最多**的类,并查看其 GC Root 路径,找到是谁阻止了它们被回收。
总结与最佳实践
| 命令 | 目的 | 使用时机 |
|---|---|---|
jcmd PID GC.heap_info |
快速健康检查 | 日常监控、性能调优初期。 |
jcmd PID GC.class_histogram |
寻找"嫌疑犯" | 初步怀疑内存被特定类占用时。 |
jcmd PID GC.heap_dump |
深度取证分析 | 怀疑内存泄漏、发生OOM时,必须操作。 |
jcmd PID GC.run |
主动触发GC | 测试环境下验证GC行为,线上慎用。 |
黄金法则:
- 优先使用
jcmd,忘掉jmap。 - 线上分析,"生成堆转储 -> 下载到本地 -> 用MAT分析" 是标准流程。
- 为关键应用设置
-XX:+HeapDumpOnOutOfMemoryErrorJVM参数,让它在OOM时自动生成堆转储,这是生产环境的救命稻草。
通过结合 jcmd 命令的快速诊断和 MAT 的深度分析,你可以系统地定位和解决绝大多数Java堆内存问题。先从 GC.heap_info 和 GC.class_histogram 用起,遇到复杂问题再生成堆转储深入分析。