async-profiler如何追踪含JIT优化方法的调用栈并生成火焰图?
async-profiler 如何在JIT优化场景下生成完整火焰图?
async-profiler之所以能穿透JIT的内联、代码优化等操作,还原出原始调用栈,核心是深度绑定HotSpot VM的原生能力,而非自己实现一套栈解析逻辑。具体实现和调用栈还原方式如下:
1. 依托HotSpot的JIT事件与元数据追踪
async-profiler通过JVMTI接口和HotSpot专属的内部API,注册了JIT编译相关的回调事件。当JVM执行方法内联、代码替换、逃逸分析优化时,这些回调会实时记录下优化前后的映射关系——比如哪个内联方法属于哪个调用者,编译后的代码块对应哪些原始Java方法。
2. 采样地址到原始方法的映射逻辑
当async-profiler完成CPU采样(不管是基于Linux perf_events的硬件采样,还是HotSpot的软件采样)拿到指令地址后,会做以下几步还原:
- 查HotSpot维护的Code Cache映射表,定位该地址所属的编译代码块(nmethod)
- 从nmethod中提取HotSpot嵌入的调试元数据,这份数据里包含了指令地址到原始Java方法、源代码行号的对应关系——哪怕方法被内联,元数据里也会完整保存内联调用链
- 把这些元数据拼接成原始的调用栈,而不是只显示优化后的顶层方法
3. 内联方法的栈帧还原细节
当方法A被内联到方法B中时,HotSpot会在生成的nmethod里嵌入内联栈帧的层级数据。async-profiler解析采样地址时:
- 会遍历这些内联数据,把被内联的A方法重新插入到调用栈的对应位置(放在B方法的上层)
- 最终生成的火焰图里,会完整展示A→B的调用关系,和未发生内联时的调用链一致
4. 原始方法信息的留存机制
async-profiler会主动缓存并实时查询以下数据:
- 所有Java方法的全限定名、方法签名,无论是否被JIT编译
- JIT优化的完整记录,包括内联日志、代码替换记录
- HotSpot的符号表与调试元数据,确保机器指令地址能准确映射回原始方法
如何获取原始调用图与信息?
- 默认采样即可:直接用
./profiler.sh -d 30 -f flamegraph.html <pid>生成的火焰图,已经自动还原了内联和JIT优化后的原始调用栈 - 导出结构化数据:通过
-o collapsed参数导出采样结果,每条记录都是完整的原始调用链,可用于后续分析 - 查看优化细节:添加
-v参数运行async-profiler,日志中会输出JIT优化的详细事件,包括哪些方法被内联、替换的具体信息
内容的提问来源于stack exchange,提问作者choxsword
相关产品推荐
相关产品推荐

