CPU Profiling 火焰图
火焰图(Flame Graph)是 Brendan Gregg 发明的一种可视化方法,能直观展示 CPU 时间的分布。它已经成为性能分析领域的标准工具。
火焰图原理
火焰图基于采样剖析。每次采样时,记录当前线程的调用栈。重复数千次后,统计每个调用栈出现的次数。
如何读懂火焰图
火焰图的核心解读原则:
- 从下往上看:最底层是调用入口,往上是被调用的方法
- 从宽往窄看:越宽的方框表示该方法消耗的 CPU 时间越多
- 从尖顶往下钻:顶层往往是真正的热点
火焰图类型
On-CPU 火焰图
展示 CPU 正在执行代码的时间。
Off-CPU 火焰图
展示 CPU 在等待 I/O、锁、GC 等的时间。
Memory 火焰图
展示内存分配热点的火焰图。
Lock 火焰图
展示锁竞争的火焰图。
async-profiler 使用
async-profiler 是 Java 性能剖析的利器,支持生成多种火焰图。
安装
基本使用
CPU
常用选项
生成对比火焰图
火焰图实战解读
典型问题:序列化占用大量 CPU
找到序列化热点后,可以考虑:
- 减少序列化对象的大小
- 使用更快的序列化库(Kryo/Protobuf)
- 避免不必要的序列化
典型问题:正则表达式慢
正则表达式每次调用都需要编译。解决方案是预编译正则:
典型问题:GC 时间占比高
finalize() 方法会增加 GC 压力。应该使用 AutoCloseable 替代。
本章小结
火焰图是性能分析的核心工具:
- 原理:基于采样的调用栈可视化
- 解读:下到上是调用链,宽度是时间占比
- 工具:async-profiler 生成 Java 火焰图
- 类型:On-CPU/Off-CPU/Memory/Lock
学会读懂火焰图,是性能工程师的必备技能。
延伸思考
为什么火焰图顶端的函数往往不是问题的根源?
因为火焰图的宽度代表"在这个函数中消耗了多少时间",但真正消耗时间的地方可能在:
- 被调用的子函数(往上看)
- 锁等待(看 Off-CPU 火焰图)
- GC 暂停(看 GC 专用火焰图)
真正的问题往往隐藏在火焰图的某个分支中,需要深入挖掘。