jfr能每10ms采样线程栈,稳定捕获毫秒级抖动,而top仅显示整体cpu率、jstack为单次快照无法捕捉瞬时尖峰;必须用jcmd动态启动,关键事件包括jdk.executionsample、jdk.jitcompilation、jdk.threadstart等。

为什么生产环境 CPU 抖动必须用 JFR 而不是 top 或 jstack
因为 top 只能看到整体 CPU 使用率,jstack 是单次快照、无法捕捉瞬时抖动(比如 200ms 的尖峰),而 JFR 的 jdk.ExecutionSample 事件默认每 10ms 采样一次线程栈,能稳定捕获毫秒级热点方法——这是定位 JIT 逆优化、锁争用、JSON 序列化爆炸等抖动根因的唯一可靠方式。
如何在不重启服务的前提下开启高精度 CPU 录制
生产环境禁止重启,必须用 jcmd 动态启动。关键点在于:采样频率要够高,但不能压垮 JVM;录制时间要覆盖抖动窗口,又不能无限写盘。
- 先查进程 ID:
jcmd -l - 启动 30 秒高频录制(含 JIT 和线程事件):
jcmd <pid> JFR.start name=cpu-burst settings=profile duration=30s filename=/tmp/cpu-burst.jfr maxsize=50M</pid> - 若已知抖动周期(如每 5 分钟一次),可用
delay=4m30s延迟启动,避免提前录制浪费空间 - 务必加
maxsize=50M,否则环形缓冲区溢出可能丢掉抖动前的关键 JIT 逆优化事件
哪些 JFR 事件对分析 CPU 抖动最关键
抖动不是单纯“CPU 高”,而是某类事件集中爆发。只看 jdk.CPULoad 没用,必须关联以下三类事件:
你接手一个需求时,是不是经常这样:"改一个小字段 → 结果把不相关的代码也改了"、"需求说得很模糊 → 做着做着发现跑偏了"、"数据库加个字段 → 上线才发现漏了数据兼容"、"做了个新功能 → 一个月后自己都忘了当时怎么设计的"、"写到一半被中断 → 再回来不知道从哪继续";这个 Skill 就是专门解决这些问题的。 它会自动探测你的项目环境(JDK、Spring Boot、ORM、数据库、前端框架),记在
-
jdk.ExecutionSample:定位具体哪行代码在抖动期间被采样最多(火焰图基础) -
jdk.JITCompilation和jdk.JITUncompilation:确认是否发生 C2 逆优化(常见于 JSON 库分支预测失败) -
jdk.ThreadStart和jdk.JavaThreadPark:检查是否因线程池扩容导致大量线程创建/阻塞
如果 jdk.JITUncompilation 事件在抖动开始前 1–2 秒密集出现,基本可锁定是 JIT 导致的瞬时性能坍塌。
用命令行快速验证抖动时刻的热点方法(不用 JDK Mission Control)
JDK Mission Control 在生产环境常不可用,jfr CLI 工具足够做初步判断:
- 导出抖动期间的执行样本:
jfr print --events jdk.ExecutionSample --begin "2026-04-18T05:28:10" --end "2026-04-18T05:28:12" cpu-burst.jfr > samples.txt - 统计最频繁的方法调用栈:
grep "stackTrace" samples.txt | sort | uniq -c | sort -nr | head -10 - 重点看是否集中出现在
com.fasterxml.jackson.、java.util.regex.或自定义的xxxService.process()上
真正容易被忽略的是:JFR 默认不记录 native 方法栈(如 JNI 调用),如果抖动发生在 Netty 的 epoll_wait 或数据库驱动 native 层,jdk.ExecutionSample 会显示为 Unknown —— 这时得结合 perf record -g -p <pid></pid> 补充采集。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










