核心概念
Java Flight Record 提供一个低开销的数据收集框架,用于对 Java 应用程序和 HotSpot JVM 进行故障排除。Flight Recorder 记录源自应用程序、JVM和操作系统的事件
Flight Record,顾名思义,相当于飞机黑匣子里保存的飞行记录
事件
JFR
在Java应用运行时收集对应发生的事件,主要有三种类型的事件提供给JFR收集:
- 即时事件:一旦事件发生会立即进行数据记录
- 持续事件:如果持续时间超过指定阈值则进行数据记录
- 简单事件:用于记录应用所在系统的活跃指标(例如CPU,内存等)
Java Flight Recorder (JFR) 可以监听和记录各种事件,包括但不限于以下几类:
- 方法耗时:JFR 可以记录方法的执行时间,用于分析和优化程序的性能。
- 垃圾收集:JFR 可以记录垃圾收集器的活动和性能指标,包括吞吐量、停顿时间和对象分配等。
- 线程活动:JFR 可以记录线程的创建、销毁、休眠和唤醒等活动,用于分析并发和线程相关的性能问题。
- 锁竞争:JFR 可以记录锁的竞争和等待情况,用于分析多线程程序中的死锁和竞争问题。
- I/O 操作:JFR 可以记录文件读写、网络传输等 I/O 操作的性能指标和耗时,用于分析和优化 I/O 性能。
- GC 周期:JFR 可以记录整个 GC 周期的信息,包括新生代、老年代和永久代的使用情况和回收效率等。
- 内存分配:JFR 可以记录内存的分配和使用情况,包括堆内、堆外和直接内存的分配和释放情况。
除了上述事件,JFR 还支持自定义事件,您可以根据应用程序的需求自定义记录特定事件和指标。这些事件和指标可以帮助开发人员了解应用程序的行为和性能状况,并进行性能优化和故障排查。
缓冲机制和二进制数据格式
线程将事件无锁地写入ThreadLocal
缓冲区。一旦ThreadLocal
缓冲区填满,它就会被提升为全局内存循环缓冲区系统,该系统维护最新的事件数据。根据配置,最旧的数据要么被丢弃,要么被写入磁盘,从而允许连续保存历史记录
事件模型以
little endian base 128
的形式编码的二进制格式实现。磁盘上的二进制文件具有扩展名.jfr
,并使用保留策略进行维护和控制
作为说明性示例,类加载事件包含描述其发生时间的时间戳、描述时间跨度的持续时间、线程、堆栈跟踪以及三个事件特定有效负载字段、加载的类和关联的类加载器。事件的大小总共为 24 字节。
<memory address>: 98 80 80 00 87 02 95 ae e4 b2 92 03 a2 f7 ae 9a 94 02 02 01 8d 11 00 00
- 活动规模[98 80 80 00]
- 事件ID[87 02]
- 时间戳[95 ae e4 b2 92 03]
- 期间[a2 f7 ae 9a 94 02]
- 线程ID[02]
- 堆栈跟踪 ID[01]
- 有效负载[字段]
- 加载类:[0x8d11]
- 定义类加载器:[0]
- 启动类加载器:[0]
JFR 诊断
在 JVM 命令启动JFR
-XX:StartFlightRecording
bin/jcmd 工具启动JFR
# 启动JFR
jcmd <pid> JFR.start
# dump
jcmd <pid> JFR.dump filename=recording.jfr
# 停止JFR
jcmd <pid> JFR.stop
命令参数详见 JFR命令参考
JFR 解析
输出jfr文件后,可以使用JDK Mission Control
分析工具对各种性能指标进行分析。可以直接使用JFR 解析命令查看摘要信息和事件流
JDK Mission Control
JDK Mission Control
是一个强大的性能分析工具,它包含了对JFR文件进行可视化分析的功能。可以使用JDK Mission Control
打开JFR文件,查看各种性能指标、方法调用树、线程活动等信息,并进行高级分析和故障排查。
JFR 解析命令
jfr print <filename.jfr>
部分JFR文件的摘要信息和事件流
jdk.CodeCacheStatistics {
startTime = 16:13:08.344
codeBlobType = "CodeHeap 'non-nmethods'"
startAddress = 0x7FE6A1715000
reservedTopAddress = 0x7FE6A1CA4000
entryCount = 1134
methodCount = 0
adaptorCount = 1046
unallocatedCapacity = 3.7 MB
fullCount = 0
}
jdk.CodeSweeperStatistics {
startTime = 16:13:08.344
sweepCount = 72
methodReclaimedCount = 11991
totalSweepTime = 3.09 s
peakFractionTime = 208 ms
peakSweepTime = 208 ms
}
jdk.GCConfiguration {
startTime = 16:13:08.344
youngCollector = "N/A"
oldCollector = "Z"
parallelGCThreads = 2
concurrentGCThreads = 1
usesDynamicGCThreads = true
isExplicitGCConcurrent = false
isExplicitGCDisabled = true
pauseTarget = N/A
gcTimeRatio = 99
}
使用实例
自动分析结果
JMC分析
事件浏览器
HotSpot JVM 中的对象指针压缩
总结
- 低开销的性能监控:JFR 是与 JVM 集成的轻量级性能监控工具,可以在不影响应用程序性能的情况下实时收集和记录各种性能数据。与其他性能工具相比,JFR 的性能开销非常低,几乎可以忽略不计
- 实时和历史数据记录:使用 JFR,您可以实时记录应用程序的性能数据,例如线程活动、方法执行时间、垃圾收集等。您还可以通过配置持久化设置,将记录的数据保存为 JFR 文件,以供后续分析和排查问题
- 低停顿垃圾收集(Low-Pause Garbage Collection):JFR 可以捕获 Java 垃圾收集器的详细信息,包括停顿时间、吞吐量、对象分配等。这些数据可以帮助您了解垃圾收集器的性能特征并进行优化
- 生产环境监控:使用 JFR,您可以在生产环境中实时监控应用程序的性能和健康状况。通过收集关键指标,您可以及时发现和解决潜在的问题,避免应用程序性能下降或故障
- 高度可定制性:JFR 提供了丰富的配置选项,可以根据您的需求定制性能监控的粒度和数据采集。您可以选择感兴趣的事件、添加自定义事件和属性,以满足您特定的监控需求
- 集成与分析工具:JFR 数据可以与 JDK Mission Control 等工具集成,提供直观的可视化界面和高级分析功能。开发人员可以使用这些工具快速定位性能问题,并进行优化
总而言之,Java JFR是一个功能强大且易于使用的性能监控和故障诊断工具,可以帮助开发人员优化Java应用程序的性能,并提高应用程序在生产环境中的稳定性
参考资料:
- JEP 328: Flight Recorder
- Java Platform, Standard Edition Java Flight Recorder Runtime Guide
- JFR-Java Flight Record
- JEP 167:基于事件的 JVM 跟踪
- JDK Mission Control
- 深度探索JFR - JFR详细介绍与生产问题定位落地