如何通过JFR采样分析获取用户方法的纳秒级起止时间?
关于JFR获取用户方法纳秒级起止时间的解答
Great question—let’s break this down clearly, since JFR’s approach to method timing balances overhead and detail perfectly for what you’re asking.
1. 采样模式:低开销下获取绝大多数方法的时间趋势
JFR的核心采样事件(jdk.ExecutionSample)确实依赖纳秒级时间戳来计算热点方法占比,而且你完全可以提取这些数据。不过要明确:
- 采样是周期性触发的(默认10ms,可按需调整),它不会记录每一个方法的完整起止时间,而是捕获采样瞬间正在执行的方法栈。但通过统计这些采样数据,你能得到绝大多数高频/耗时用户方法的执行时间分布,开销极低(通常<1%,远低于插桩)。
- 怎么获取这些数据?
- 启动JFR时用默认的profile配置(已经包含采样):
jcmd <pid> JFR.start settings=profile - 事后分析时,用JDK Mission Control(JMC)打开录制文件,在「Method Profiling」面板就能看到每个方法的采样时间戳;或者用
jfr analyze命令批量提取jdk.ExecutionSample事件的timestamp和stackTrace字段,这些时间戳都是纳秒级的。
- 启动JFR时用默认的profile配置(已经包含采样):
2. 事件模式:获取全部用户方法的精确起止时间
如果你的需求是完整记录每一次用户方法调用的精确纳秒级起止时间,JFR也能做到,而且开销比手动插桩小很多:
- JFR内置了
jdk.MethodEnter和jdk.MethodExit两个事件,分别记录方法进入和退出的精确纳秒时间戳,两者的差值就是方法的执行时长。 - 默认情况下这两个事件是关闭的,因为它们的开销比采样高(取决于方法调用频率,一般在1%-5%区间),但你可以通过自定义配置开启:
- 创建一个配置文件(比如
method-timing.jfc),内容如下:<?xml version="1.0" encoding="UTF-8"?> <configuration version="2.0"> <event name="jdk.MethodEnter"> <setting name="enabled">true</setting> <setting name="stackTrace">true</setting> </event> <event name="jdk.MethodExit"> <setting name="enabled">true</setting> <setting name="stackTrace">true</setting> </event> </configuration> - 启动JFR时指定这个配置:
jcmd <pid> JFR.start settings=method-timing.jfc - 分析时,在JMC里筛选这两个事件,就能看到每一次方法调用的
eventTime(纳秒级),轻松计算执行时长。
- 创建一个配置文件(比如
3. 平衡开销与精度的最佳实践
如果你想兼顾低开销和尽可能多的方法时间数据,可以试试这两个技巧:
- 针对核心业务方法开启精确事件:在配置文件里用
include规则过滤,只记录特定包/类的MethodEnter/Exit事件,其他方法用采样覆盖 - 调整采样频率:把默认的10ms间隔降到1ms,这样采样覆盖的方法更多,开销仍然可控(一般<2%)
最后要确认的是:JFR的时间戳都是基于JVM的高分辨率时钟实现,精度确实是纳秒级的,完全可靠。
内容的提问来源于stack exchange,提问作者user2529617
相关产品推荐
相关产品推荐

