You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过编程方式使用JFR对调用栈进行采样?

用JFR实现10ms频率调用栈采样及周期性事件的可行性

完全可以用周期性事件获取栈追踪来实现你的需求,JFR本身就支持这种场景,甚至有现成的内置事件可以直接用,也能自定义周期性事件来完成。下面分两种方案说明:

方案一:使用JFR内置的执行采样事件(推荐)

JFR自带的jdk.ExecutionSample事件就是专门做调用栈采样的,默认配置下采样间隔可能不是10ms,但你可以通过参数调整:

  • 命令行启动时直接指定:
    java -XX:StartFlightRecording=settings=profile,duration=30s,filename=sample.jfr,stackdepth=256,period=10ms YourMainClass
    
    其中period=10ms就是设置采样间隔为10毫秒,stackdepth可以调整栈追踪的最大深度。
  • 如果通过JFR API启动录制,也可以在配置中修改采样间隔:
    Recording recording = new Recording();
    recording.enable("jdk.ExecutionSample").withPeriod(Duration.ofMillis(10)).withStackTrace(true);
    recording.start();
    // 程序运行逻辑
    recording.stop();
    recording.dump(Paths.get("sample.jfr"));
    

录制完成后,用JDK自带的jfr analyze命令或者Java Mission Control(JMC)打开录制文件,就能查看方法调用的频率统计——JMC的"方法采样"视图会直接展示被采样次数最多的方法,火焰图也能直观呈现调用栈的热点。

方案二:自定义周期性事件

如果你需要更定制化的逻辑,也可以自己写一个带@PeriodicEvent注解的事件类来定期采集栈追踪:

import jdk.jfr.Event;
import jdk.jfr.Label;
import jdk.jfr.Period;
import jdk.jfr.StackTrace;

@Label("Custom Stack Trace Sampler")
@Period("10ms") // 设置10ms触发间隔
@StackTrace(true) // 自动记录触发时的调用栈
public class CustomStackSampleEvent extends Event {
}

启动JFR录制后,这个事件会由JFR的后台线程自动周期性触发,每次触发都会记录当前线程的调用栈。不过要注意:

  • 自定义事件默认只记录触发线程的栈,如果需要采样所有运行中的线程,得在事件中手动遍历线程并获取栈,这样会带来更大的性能开销。
  • 10ms的采样频率不算低,要先在测试环境评估对目标程序的性能影响——一般JFR采样开销很小,但高频采样仍需验证后再上线。

关键注意点

  • 采样间隔设置为10ms后,实际触发可能因为JVM调度有微小偏差,但整体会保持在预期频率附近。
  • 开启栈追踪会增加一些内存和CPU开销,建议先在测试环境验证性能影响。
  • 分析时,统计方法出现的次数就能找出最频繁调用的方法,JMC的工具已经做好了聚合统计,无需手动解析栈帧。

内容的提问来源于stack exchange,提问作者myles215

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.21 17:54:34