必须启用-XX:+FlightRecorder参数,Java 11+默认禁用;jcmd动态录制需显式指定name、duration、settings等参数,避免默认60秒录制;故障分析禁用浏览器打开.jfr,应使用JMC或jfr命令行工具;长期监控与突发故障需分策配置,禁用disk=true+maxsize=0组合。

必须先确认-XX:+FlightRecorder已启用
不加这个参数,jcmd 执行 JFR.start 会直接报错 Unknown diagnostic command。Java 11+ 默认禁用,哪怕用的是 Temurin 或 Zulu 这类主流 OpenJDK 构建版,容器镜像或启动脚本也常覆盖掉该参数。验证方式很简单:java -XX:+FlightRecorder -version 不报错即通过;若报 Unrecognized VM option,说明版本太低(如 OpenJDK 8u252 之前),需升级或补 -XX:+UnlockCommercialFeatures(不推荐)。
jcmd动态录制要带name、duration和settings
故障时刻不能靠“默认录制”——它只录 60 秒、缓冲区约 10MB、无文件名、无上下文,事后根本无法定位哪次是故障时段。必须显式控制:
-
name=crash-20261014-0905:用时间戳命名,方便归档和关联监控告警 -
duration=180s:明确终止,避免拖垮老年代(尤其 GC 压力大时) -
settings=profile:比 default 多采集jdk.ExecutionSample(方法栈)、jdk.ThreadPark(锁阻塞)、jdk.GCPhasePause(GC 暂停),但避开类加载、JIT 编译等高开销事件 -
maxsize=500M:防磁盘写满;disk=false(默认)更安全——数据走内存环形缓冲,开销更低
完整命令示例:jcmd 12345 JFR.start name=crash-20261014-0905 settings=profile,duration=180s,maxsize=500M,filename=/var/log/jfr/crash-20261014-0905.jfr
故障中别用浏览器打开.jfr文件
3 分钟高负载录制轻松产出 100MB+ 的二进制文件,浏览器加载会触发前端 JS 渲染数万级事件(比如 jdk.ThreadParkEvent),极易卡死或 OOM。必须用本地 jmc(JDK Mission Control):它流式解析 + 懒加载,支持 500MB+ 文件。若没装 JMC,可用 jfr print 快速筛关键事件:jfr print --events "jdk.CPULoad,jdk.GarbageCollection,jdk.ExecutionSample" crash-20261014-0905.jfr,或导出 CSV:jfr export --events jdk.ExecutionSample crash-20261014-0905.jfr --output hot-methods.csv。
长期监控和突发故障的配置逻辑完全不同
生产环境里,“持续开启”和“按需启停”是两套策略,混用会出问题:
- 长期监控:JVM 启动时固定开启,用
-XX:StartFlightRecording=delay=0s,duration=0s,filename=/var/log/jfr/continuous.jfr,maxsize=2G,settings=profile(duration=0s表示持续录制) - 突发故障:只用
jcmd动态启停,单次不超过 5 分钟,且避免在 CPU >85% 的节点上高频启停(比如每 30 秒一次),否则刷盘和 GC 压力会反噬性能
最容易被忽略的是:disk=true + maxsize=0(无限落盘)这种组合,在故障期间可能瞬间打满磁盘 IO,导致 JVM 线程阻塞——而你正想查的就是阻塞原因。


















