性能剖析与火焰图

用采样剖析定位热点代码:perf、async-profiler 等工具生成火焰图,按 CPU、内存或锁维度查看调用栈占比,先定位再优化。

剖析与火焰图怎么用

性能剖析用采样方式记录调用栈:在代表性负载下隔一段时间抓一次栈,样本足够多之后,栈出现频率就近似反映各代码路径的资源占用。火焰图把这些样本横向展开——横轴宽度是样本占比,纵向是调用层次,因此一眼能看出“谁真正占用了 CPU”。它的价值在于把优化对象从猜测变成证据:先定位占比高的自身消耗,再决定改哪里。

基本信息

常见工具perf(Linux 内核采样)、async-profiler(JVM)、pprof(Go)
维度CPU 热点、内存分配、锁竞争、IO 等待,一次聚焦一个
读图要点找“自身占比高”的宽块,而不是只看顶部被调用的壳函数
前置条件负载需可复现且贴近生产的数据规模与请求比例

典型使用场景

  • CPU 使用率高但不知原因:定位具体函数与调用路径
  • 接口延迟高而依赖正常:确认耗时是计算、序列化还是锁等待
  • 内存分配频繁:按分配维度查看对象创建热点,减少临时对象
  • 锁竞争排查:按锁维度查看等待栈,找出争用点
  • 优化收益验证:改前改后同负载复采,对比火焰图形状变化

流程

流程
1. 确认场景可复现,采集代表性负载下的样本
2. 生成火焰图:宽度=样本占比,颜色区分维度
3. 找自身占比高的函数(而非被调用的壳函数)
4. 优化后复采对比,验证收益

维度与判断

维度能看到什么常见结论方向
CPU各调用栈占用 CPU 的比例算法复杂度、重复计算、序列化开销
内存分配对象分配的位置与数量临时对象过多、集合无预设容量
锁锁等待与竞争栈临界区过大、共享结构粒度粗
IO 等待阻塞在读写上的比例同步 IO、批量过小、连接复用不足

操作要点

  • 准备代表性负载:请求比例与数据规模贴近生产,否则热点会失真
  • 选择维度:CPU 热点、内存分配、锁竞争,一次聚焦一个
  • 采样生成火焰图,自下而上找自身占用高的分支
  • 定位函数后核对代码路径与调用频次,评估优化空间是否值得
  • 修改后同负载复采,对比火焰图与指标变化,把有效优化固化成回归
采样剖析有观测误差,优化前后要用相同方法与负载复测,避免被噪声误导;单次对比的差异要大到能排除噪声才可采信。
在生产环境做高频采样会带来额外开销:采样频率、采样时长与目标进程的选择都要事先评估,必要时先在预发环境复现。

易错点

  • 凭经验猜测热点,优化后收益无法证实,改了一堆代码但指标没变
  • 在非代表性负载下采样,结论不可用,优化方向与实际瓶颈错位
  • 只看函数名不看调用路径:同名函数在多条路径上,优化对象选错
  • 频繁采样本身带来开销,在高负载时段采集导致被测系统表现失真
  • 优化后不复测,收益与代价都不清楚,改动被后续重构无意中回退

数据来源与参考

  • 《性能之巅(第 2 版)》(Gregg):火焰图
  • Brendan Gregg 博客:Flame Graphs
​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌