bigywater.tech
Java · 205

JFR:用事件流观察 JVM 的运行状态

JFR 能记录 JVM 的哪些运行状态、怎么读?这篇用一个有锁争用的小程序实际录制,看文件大小、事件种类、具体事件字段和配置(JMX 与 NMT 在后面,JFR 与线程转储互补)。

185 种
3 秒记录里产生记录的事件种类数
240 条
jdk.JavaMonitorEnter(锁争用)事件数,带 previousOwner 与栈
20 ms / 10 ms
default / profile 配置里 ExecutionSample 的采样周期

开启录制

实测 · 本机执行输出
  [0.189s][info][jfr,startup] Started recording 1. No limit specified, using maxsize=250MB as default. | [0.189s][info][jfr,startup] | [0.189s][info][jfr,startup] Use jcmd 64663 JFR.dump name=1 to copy recording data to file. | app done
  记录文件 rec.jfr 大小 575 KB

summary

实测 · 本机执行输出
  Version: 2.1
  Chunks: 1
  Start: 2026-10-03 08:40:11 (UTC)
  Duration: 3 s
  jdk.GCPhaseParallel 6806 172577
  jdk.PromoteObjectInNewPLAB 955 16079
  jdk.NativeLibrary 946 78946
  jdk.ObjectAllocationSample 900 12699
  jdk.SystemProcess 805 82171
  jdk.ModuleExport 505 4912
  jdk.BooleanFlag 490 14424
  jdk.ActiveSetting 360 10031
  jdk.TenuringDistribution 330 3364
  jdk.JavaMonitorEnter 240 5272
  jdk.LongFlag 162 5092
  jdk.ModuleRequire 153 1377
  共 185 种事件产生了记录

具体事件

实测 · 本机执行输出
  [jdk.GarbageCollection] 共 22 条;前 3 条的关键字段:
    jdk.GarbageCollection {
     startTime = 16:40:11.122 (2026-10-03)
     duration = 1.22 ms
     gcId = 1
     name = "G1New"
     cause = "G1 Evacuation Pause"
     sumOfPauses = 1.22 ms
     longestPause = 1.22 ms
     eventThread = "VM Thread" (osThreadId = 18691)
    }
  [jdk.JavaMonitorEnter] 共 240 条;前 2 条的关键字段:
    jdk.JavaMonitorEnter {
     startTime = 16:40:11.067 (2026-10-03)
     duration = 49.8 ms
     monitorClass = java.lang.Object (classLoader = bootstrap)
     previousOwner = "holder" (javaThreadId = 33)
     address = 0x75E8CF2E60
     eventThread = "worker-3" (javaThreadId = 32)
     stackTrace = [
     App.lambda$main$0(long) line: 5
     java.lang.Thread.run() line: 1583
     ]
    }
  [jdk.ExecutionSample] 共 0 条;前 0 条的关键字段:

配置

实测 · 本机执行输出
  jdk.ExecutionSample:default = {'enabled': 'true', 'period': '20 ms'};profile = {'enabled': 'true', 'period': '10 ms'}
  jdk.JavaMonitorEnter:default = {'enabled': 'true', 'stackTrace': 'true', 'threshold': '20 ms'};profile = {'enabled': 'true', 'stackTrace': 'true', 'threshold': '10 ms'}

分步演示

JFR
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / OpenJDK(Temurin 17.0.20、Homebrew 21.0.12 与 27,每篇注明实际用的版本);用 javac 编译、java 直接运行,需要第三方库时用 Maven 解析依赖;计时用 System.nanoTime,数字每次运行会有小幅抖动。JDK 21.0.12,macOS,G1;3 秒录制,4 个工作线程与 1 个持锁线程
    • 没有验证:ExecutionSample 数量偏少的原因、JFR 对吞吐的开销、jcmd JFR.start/dump/stop 的在线用法、JFR 事件流(RecordingStream)的实时消费、自定义事件(@Event)、堆分配采样的内容;耗时与计数来自一次运行
    京ICP备2026067502号-1京公网安备11010502063487号