火焰图

义项:性能分析可视化图表
火焰图

火焰图(Flame Graph)是一种把软件性能剖析得到的调用栈数据画成层叠方块的图表,用于快速定位程序里的性能热点。图中每个方块对应一个函数,宽度反映该函数在采样中出现的比例,纵向层级反映调用栈深度。它由计算机工程师 Brendan Gregg 于 2011 年提出,此后成为 CPU、内存、阻塞等多种性能分析的通用可视化方式。

目录
  1. 定义
  2. 原理
  3. 发展历程
  4. 应用
  5. 局限
  6. 参见

定义

火焰图是一种用于可视化软件性能剖析数据的图表,把采样得到的调用栈数据组织成由许多矩形堆叠而成的图形,借此从调用栈中找出一段程序里最耗资源的代码路径[1][2]。它的图形下宽上尖、形似火焰,名称即由此而来[3]。

在火焰图中,一个矩形代表一个函数或方法,矩形的宽度表示该方法在全部采样中所占的比例,矩形的高度位置表示该方法在调用栈中的深度,函数之间的层层嵌套则用上下排列的方式表达[4]。图形通常可以交互:鼠标悬停可看到完整函数名、样本数与占比,点击某一层可横向放大,还能用关键词或正则表达式检索函数名并高亮匹配结果[2]。

原理

火焰图本身不采集数据,数据来自剖析器对调用栈的采样。剖析器以固定频率中断目标程序并记录当时的调用栈,一份剖析结果中往往包含成千上万条调用栈记录,单纯的文本输出难以阅读,火焰图的作用就是把这类数据压缩成一张可读的图[2][5]。

生成过程通常分三步:先用剖析器取得调用栈,再把调用栈转换成每行一条、以分号分隔函数名并在行尾附上计数的折叠格式,最后由绘制脚本把折叠数据渲染为 SVG 图[2]。Brendan Gregg 发布的原始实现采用 Perl 语言编写并以开源方式发布,其中包含面向不同剖析器的转换程序和负责绘图的 flamegraph.pl 脚本[2]。

读图时可以把握几条规则:纵轴是调用深度,底部为入口函数、顶部为采样时正在执行的函数;横轴按字母序或地址序排列,目的是让相同的栈帧合并成更宽的方块,并不代表时间先后;方块的宽度是采样占比,而不是某次调用的实际时长[6][5]。顶边较宽的平顶形态通常意味着某函数独占资源,是定位瓶颈的首要线索[6]。

每个方块还可以区分自身值与总值两个量:总值是包含其调用的子函数的完整宽度,自身值是该函数位于栈顶的采样占比。总值大而自身值小的函数多为调度或框架代码,本身不直接消耗资源,优化时应优先关注自身值高的函数[6]。常见工具在表格里以“自身大小”和“总大小”两列呈现这两项数据[4]。

发展历程

火焰图由计算机工程师 Brendan Gregg 于 2011 年提出,其原始实现以开源软件形式发布,被用于快速识别程序中的性能热点[1]。2016 年 5 月,相关方法整理为《The Flame Graph》一文发表于《Communications of the ACM》,系统介绍了生成步骤、读图方法和在阻塞分析等方向上的扩展[2][7]。

此后火焰图逐步被各类平台内置。流处理框架 Apache Flink 从 1.13 版本开始原生支持火焰图,1.17 版本进一步提供了细化到单个子任务的视图[8]。云端可观测性产品与图表工具也陆续把火焰图作为标准的剖析数据展示形式[4][9]。

应用

最典型的用法是 CPU 火焰图:剖析器按固定频率采样 CPU 上的调用栈,宽度即函数占用 CPU 时间的近似比例,可用来找出占用 CPU 最多的热点函数并分析代码热路径[3]。与之互补的是 Off-CPU 火焰图,它采集线程处于阻塞状态时的调用栈,用于分析 I/O、网络等待、锁竞争和死锁造成的性能下降[8][3]。

在此基础上还衍生出多种变体:内存火焰图以内存申请次数或分配字节数为宽度,用于排查内存泄漏与占用偏高的问题;冷热火焰图把 On-CPU 与 Off-CPU 数据合并展示;差异火焰图对比两次剖析结果,用于观察性能回归或调优前后的变化[3][2]。

在使用场景上,火焰图常与持续性能剖析结合,在开发、预生产乃至生产环境中长期采集代码级性能数据[10]。移动端也有专门实现,例如 Android 的 Inferno 可基于 simpleperf 采集原生应用的调用栈并生成自包含的 HTML 报告[11]。

局限

火焰图丢失了时间信息。由于相同的调用栈会被合并,横轴不再是时间线,图中无法反映某个栈帧是何时被采集到的,也无法显示事件发生的先后顺序[12][13]。外观相近的火焰图时间图(flame chart)把横轴改为时间顺序,可以呈现时序问题,但合并程度会明显降低[14]。

结果精度受采样过程制约。宽度反映的是采样中出现的比例,无法给出函数被调用的确切次数,也不能区分某函数是单次调用耗时长还是被频繁调用[2]。采样式的 Java 剖析还可能在安全点采样而产生偏斜,并可能把等待状态误判为占用 CPU[15]。

数据缺失会直接导致图形失真。部分剖析器会截断调用栈深度,若编译器把帧指针寄存器复用为通用寄存器,基于帧指针的栈回溯就会失效,需要改用其他编译选项或回溯方式;即时编译代码缺少标准符号表时,函数名还会显示为十六进制地址[14]。当调用栈无法回溯到统一的根时,图形会出现大量无法合并的碎片[11]。

Off-CPU 火焰图在某些情形下结论不充分。当一个线程在等待另一个线程的信号时,仅看阻塞方的栈无法说明对方为何耗时过长,而唤醒它的线程可能又在等待第三个线程,单个唤醒火焰图未必足够。此外,采样本身会带来一定开销,因此部分平台把火焰图作为需要手动开启的功能,并建议在生产环境中谨慎使用[8]。

参见

  • 性能剖析 —— 火焰图所服务的数据采集与分析过程。

  • 调用栈 —— 火焰图纵向层级所表达的基本结构。

  • Brendan Gregg —— 火焰图方法的提出者。

  • eBPF —— 常用于采集调用栈采样的动态追踪技术。

  • 持续性能剖析 —— 长期采集性能数据并以火焰图等方式展示的做法。

参考资料

  1. Flame graph [引用日期2026-10-29]
  2. ACM: Digital Library: Communications of the ACM [引用日期2026-10-29]
  3. 程序员精进之路:性能调优利器--火焰图 [引用日期2026-10-29]
  4. 火焰图说明 [引用日期2026-10-29]
  5. Linux CPU 性能分析工具火焰图(Flame Graphs)认知 [引用日期2026-10-29]
  6. 火焰图详解:如何读懂 CPU 火焰图,找出烧掉 CPU 的代码 [引用日期2026-10-29]
  7. acm.org 上的网页 [引用日期2026-10-29]
  8. 火焰图 # [引用日期2026-10-29]
  9. 火焰圖 - Amazon Managed Grafana - 選取您的 Cookie 偏好設定 [引用日期2026-10-29]
  10. 火焰图是怎么画出来的?Pyroscope源码解析之火焰图 [引用日期2026-10-29]
  11. inferno [引用日期2026-10-29]
  12. FlameGraph interpretation [引用日期2026-10-29]
  13. Flame Charts vs Flame Graphs [引用日期2026-10-29]
  14. Communications of the ACM [引用日期2026-10-29]
  15. Java Performance Analysis on Linux with Flame Graphs [引用日期2026-10-29]
词条评价
词条统计

浏览次数:0 次

阅读量:0 次 · 阅读完成量:0 次

最近更新:2026-10-28T18:44:59Z

历史版本

本条目引用的词条
性能剖析 调用栈 Brendan Gregg eBPF 持续性能剖析