Skip to content

JMC/JFR/火焰图

诊断的终极组合

JMC(Java Mission Control)、JFR(Java Flight Recorder)和火焰图,是 JDK 提供和配合使用的最强大的诊断工具链。JFR 是数据采集引擎,JMC 是数据可视化工具,火焰图是分析结果的图形化展示。

JFR:飞行记录器

什么是 JFR

JFR(Java Flight Recorder)是 JDK 内置的持续低开销性能分析工具。它像飞机上的黑匣子,持续记录 JVM 运行时的各种事件。

JFR 特点:
✓ 低开销:默认 < 1% CPU 开销
✓ 持续运行:可以在生产环境持续开启
✓ 丰富数据:CPU、内存、GC、线程、IO、锁等
✓ JDK 内置:无需额外安装

JFR 的事件类型

JFR 记录的事件分为多个类别:

JFR 事件类别:
├── 虚拟机(VM)
│      ├── 运行日志(vm_info)
│      ├── GC 信息(gc_*)
│      └── 类加载(class_*)

├── Java 应用程序
│      ├── 方法分析(profiler)
│      ├── 异常(exception_thrown)
│      └── 线程(thread_*)

├── 操作系统
│      ├── CPU 使用(cpu_*)
│      ├── 内存(os_mem_*)
│      └── 网络 IO(socket_*)

└── 垃圾回收
       ├── Minor GC
       └── Full GC

开启 JFR 录制

方式一:JVM 启动参数

bash
# 开启 JFR,录制数据保存到文件
java -XX:+FlightRecorder \
     -XX:StartFlightRecording=dumponexit=true,\
filename=myrecording.jfr,\
settings=profile \
     -jar myapp.jar

# 参数说明:
# dumponexit=true → JVM 退出时保存录制
# filename → 输出文件名
# settings → 预置配置(default / profile / template)

方式二:JCMD 运行时控制

bash
# 开始录制
jcmd <pid> JFR.start name=myrecording \
     settings=profile \
     filename=recording.jfr \
     duration=60s

# 查看正在运行的录制
jcmd <pid> JFR.check

# 停止录制(生成 .jfr 文件)
jcmd <pid> JFR.stop name=myrecording

# 转储录制数据
jcmd <pid> JFR.dump name=myrecording filename=dump.jfr

# 连续录制(滚动覆盖)
jcmd <pid> JFR.start name=continuous \
     settings=default \
     maxage=1h \
     maxsize=100m \
     dumponexit=true \
     filename=continuous.jfr

方式三:JMC 界面操作

JMC 操作流程:
1. 打开 JMC
2. 在左侧「JVM Browser」中找到目标 JVM
3. 右键 → 启动 Flight Recorder
4. 选择录制模板(default / profile)
5. 设置录制时长或持续录制
6. 录制结束后,自动打开分析视图

预置录制模板

模板用途开销数据量
default生产环境持续监控< 1%适中
profile详细分析< 2-3%丰富
template自定义模板可调可调
bash
# 创建自定义模板
jfr.cmd print --json --categories "gc,profiler" recording.jfr

JMC:任务控制中心

JMC 简介

JMC(Java Mission Control)是 JFR 数据的可视化分析工具。JDK 8 自带,JDK 9+ 需要从 jdk.java.net/jmc 下载。

启动 JMC

bash
# JDK 8 自带
jmc

# JDK 9+ 独立版本
/path/to/jmc/bin/jmc

JMC 界面

JMC 主界面:

左侧「JVM Browser」:
  ├── 本地 JVM
  │      └── 运行的 Java 进程
  └── 远程 JVM(通过 JMX 连接)
         └── 远程 Java 进程

右侧「分析视图」:
  ├── 自动分析(自动分析录制中的问题)
  ├── 内存(Memory)
  ├── 代码(Code)
  ├── 线程(Threads)
  ├── 文件 I/O(I/O)
  └── 环境(Environment)

自动分析

JMC 的自动分析会列出发现的问题:

自动分析报告包含:

1. 问题(Problems)
   - 高开销方法
   - GC 导致的停顿
   - 内存泄漏嫌疑人
   - 死锁

2. 信息(Info)
   - JVM 信息
   - 系统信息
   - 环境信息

3. 建议(Advisor)
   - JVM 参数优化建议
   - 代码优化建议

内存分析

内存视图展示堆和非堆内存的使用情况:

内存视图包含:

1. GC 摘要
   - GC 次数、耗时、原因

2. 堆使用量图表
   - 随时间变化的堆使用曲线

3. 对象统计
   - 按包/类分组的内存占用

4. TLAB 分配
   - 线程本地分配缓冲区统计

火焰图(Flame Graph)

火焰图是 JMC 分析结果的一种图形化展示形式。

async-profiler 生成火焰图

async-profiler 是生成火焰图的首选工具:

bash
# 安装 async-profiler
# 下载:https://github.com/async-profiler/async-profiler/releases

# CPU 火焰图
./profiler.sh -d 60 -f cpu.svg <pid>
# -d 60 → 录制 60 秒
# -f cpu.svg → 输出 SVG 文件

# 内存分配火焰图(alloc)
./profiler.sh -d 60 -e alloc -f alloc.svg <pid>
# -e alloc → 监控内存分配

# 锁竞争火焰图
./profiler.sh -d 60 -e lock -f lock.svg <pid>
# -e lock → 监控锁竞争

火焰图的阅读方法

火焰图的阅读方式(从下往上):

         ┌─────────────────────────────────────┐
         │              方法 A                    │  ← 栈顶(CPU 热点)
         │         ┌───────────────────┐       │
         │         │      方法 B          │       │
         │         │    ┌───────────┐    │       │
         │         │    │   方法 C    │    │       │
         │         │    │ ┌───────┐  │    │       │
         │         │    │ │ 方法 D │  │    │       │
─────────┼─────────┼────┼─┼───────┼──┼────┼───────┼──  ← 基线(所有栈的公共起点)
         │         │    │ │ JDK   │  │    │       │
         │         │    │ │ Thread│  │    │       │
         │         │    └─┴───────┴──┘    │       │
         │         └───────────────────┘       │
         └─────────────────────────────────────┘

宽度 → 该方法在采样中出现的次数(越多越宽 = 越热)
高度 → 调用栈的深度
顶层 → CPU 热点方法

颜色:
  红色系 → CPU 消耗(默认)
  蓝色系 → 内存分配
  黄色系 → 锁竞争

从 .jfr 生成火焰图

bash
# 方式一:使用 async-profiler 直接分析 PID
./profiler.sh -d 30 -f flamegraph.svg <pid>

# 方式二:使用 JMC 导出数据,再用工具生成火焰图
# JMC → File → Export → CSV
# 使用 FlameGraph 工具生成
# perl flamegraph.pl --collapsed=result.txt > graph.svg

# 方式三:使用 JFR Flamegraphs 脚本
# jfr-flame-graph: https://github.com/chrishanth/flightrecorder/tree/master/jfr-flame-graph
java -jar jfr-flame-graph.jar recording.jfr cpu

JFR 事件与火焰图的对应

CPU 火焰图:
  采样的调用栈 → 宽度 = CPU 占用比例

Alloc 火焰图:
  对象分配的调用栈 → 宽度 = 分配速率

Lock 火焰图:
  线程等待锁的调用栈 → 宽度 = 等待时间

JFR + JMC + 火焰图 工作流

诊断工作流:

1. 开启 JFR 录制(生产环境持续运行)
   └── jcmd PID JFR.start settings=default maxage=1h

2. 发现问题,触发转储
   └── jcmd PID JFR.dump filename=issue.jfr

3. 用 JMC 分析 .jfr 文件
   └── jmc -open issue.jfr
   └── 自动分析 → 定位问题类型

4. 生成火焰图深入分析
   └── async-profiler -f flame.svg PID
   └── 从火焰图定位热点方法

5. 修复并验证
   └── 再次录制,对比改进效果

JFR 在生产环境的最佳实践

生产环境 JFR 配置:

1. 默认开启(低开销)
-XX:+FlightRecorder
-XX:FlightRecorderOptions=defaultrecording=true,settings=default

2. 持续录制,滚动覆盖
-XX:+FlightRecorder
-XX:StartFlightRecording=defaultrecording=true,\
settings=default,\
maxsize=100m,\
maxage=1h,\
dumponexit=true

3. OOM 时自动保存
-XX:+FlightRecorder
-XX:FlightRecorderOptions=defaultrecording=true
-XX:StartFlightRecording=\
dumponexit=true,\
filename=oom.jfr,\
settings=profile

4. 安全的 JMX 连接(生产环境)
-Dcom.sun.management.jmxremote
-Dcom.sun.management.jmxremote.port=9999
-Dcom.sun.management.jmxremote.authenticate=true
-Dcom.sun.management.jmxremote.ssl=true

本节小结

JMC/JFR/火焰图核心要点:

工具作用特点
JFR持续低开销的性能数据采集< 1% CPU 开销,生产环境可用
JMCJFR 数据的可视化分析自动分析问题,图形化展示
火焰图调用栈热点的图形化展示直观定位 CPU/内存热点
async-profiler生成火焰图的工具支持 CPU/alloc/lock 等多种模式

JFR 是生产环境的诊断利器——低开销、持续运行、丰富数据,配合 JMC 和火焰图,可以精准定位最隐蔽的性能问题。

下一节,我们来看 Arthas 安装/基础指令

基于 VitePress 构建