诊断工具不是越多越好。jcmd 适合即时查询与控制,JFR 适合关联 JVM 事件,VisualVM 适合交互观察,async-profiler
适合低开销 CPU、分配和锁采样。本教程让它们观察同一个有时限的 CPU 热点。
Table of contents
Open Table of contents
开始前准备
编译CPU 热点样例下载:
mvn package
java -cp target/classes dev.elaine.jvmlab.CpuHotspotSample 60
程序打印 PID 并在 60 秒后主动结束。保留这个终端,再开一个终端执行诊断命令。工具 JDK 应与目标 JVM 版本一致; 容器内还需要相同用户和 Attach 权限。
使用 jcmd 取得即时快照
先列出进程和可用命令:
jcmd -l
jcmd <PID> help
jcmd <PID> VM.version
jcmd <PID> VM.flags
jcmd <PID> Thread.print -l > threads.txt
Thread.print 的影响随线程数量增长。高峰期先采集多份间隔几秒的线程转储,再决定是否执行更重操作。Oracle 的
jcmd 参考会标出各命令影响级别。
使用 JFR 关联事件
启动 30 秒性能录制:
jcmd <PID> JFR.start name=cpu settings=profile duration=30s filename=cpu.jfr
jfr summary cpu.jfr
jfr print --events jdk.ExecutionSample cpu.jfr | head -n 80
JFR(Java Flight Recorder)能同时记录执行采样、线程、锁、GC、分配和编译事件。profile 配置比 default 采样更细,
开销也更高;生产持续录制通常使用 default,问题窗口再短时提高精度。
VisualVM 适合探索
VisualVM 能查看线程、堆、类和采样结果,适合本地与预生产交互分析。远程连接必须配置认证、TLS 和网络边界,不能为了 方便直接暴露未认证 JMX 端口。
GUI 截图只能说明某一时刻。重要结论要保存 JFR、线程转储、时间范围和过滤条件,确保其他人能复核。
async-profiler 适合热点归因
async-profiler 不是 JDK 内置工具,需要从官方项目安装适配系统的版本。典型命令为:
asprof -d 30 -e cpu -f cpu.html <PID>
asprof -d 30 -e alloc -f alloc.html <PID>
asprof -d 30 -e lock -f lock.html <PID>
CPU 采样回答“时间花在哪里”,Allocation Profile 回答“对象在哪里创建”,Lock Profile 回答“线程在哪里等待”。不要 拿 CPU 火焰图证明内存泄漏,也不要把采样占比直接当成墙钟耗时。
形成证据链
记录问题时间、部署版本、负载、PID、命令、工具版本和输出文件哈希。先用低影响快照确认方向,再提高录制强度。未经 审批不要把包含业务参数或对象内容的诊断文件上传到公共服务。
下一步
阅读内存泄漏、OOM 与 Heap Dump 实战,使用受限小堆安全复现 内存故障。