Flame Graph,即火焰图,是直观分析资源使用情况,从而判断瓶颈所在的一种图。本文介绍如何为JVM进程生成CPU/内存的火焰图。
安装所需工具
如果使用OpenJDK,还需要安装Debug工具,以JDK11为例,
- 安装
openjdk-11-dbg
:sudo apt-get install openjdk-11-dbg
- 从Github下载async-profiler:
- 若需以普通用户执行性能分析工具,还需要修改权限,方法如下(系统重启后需要重新修改):
echo 1 > /proc/sys/kernel/perf_event_paranoid # default 3 echo 0 > /proc/sys/kernel/kptr_restrict # default 0
分析CPU使用情况
先使用jps
命令查看系统运行的Java进程,记下需要分析的进程PID。
进入解压后的async-profiler
目录,执行
./profiler.sh -e cpu -d 30 -f ~/cpu-flamegraph.svg 54662
其中 -d
表示取样的时长,单位为秒。
使用
-e wall
参数可以分析Wall clock time, 与CPU时间不同的是,线程处于休眠、阻塞等的时间也会算进去,这对于分析Java程序的启动时长比较有用。
理解CPU火焰图
- 格子的宽度表示对应方法占用的CPU时间。较宽的格子表示对应方法在取样过程中总共执行总时间,有可能是这个方法单次执行了较长时间,也有可能是这个方法被多次调用引起的。
- Y轴表示栈的深度,较低(即靠近X轴)的格子是更高格子的父级栈。
可见定位CPU使用率过高问题时,需要重点关注相对较宽的格子对应的方法。
分析内存使用情况
async-profiler
除了可以进行CPU使用情况取样外,还能对堆内存使用情况取样。
先使用jps
命令查看系统运行的Java进程,记下待分析的进程PID。
进入解压后的async-profiler
目录,执行
./profiler.sh -e alloc -i 500k -d 30 -f ~/mem-flamegraph.svg 54662
-i 500k
表示平均每500KB堆内存分配时行一次取样,这个值不能太小。
理解内存火焰图
宽度对应内存使用量,所以关注较宽的格子对应的方法。
分析其它程序
提示: Debian/Ubuntu 的
perf
工具在linux-tools
包里。
- 对指定进程进行30秒采样,运行成功后会生成原始取样数据:
perf.data
perf record -F 99 -p 13204 -g -- sleep 30
- 下载并使用工具包的工具生成火焰图:
git clone --depth=1 https://github.com/brendangregg/FlameGraph cd FlameGraph/ # 将第一步里生成的`perf.data`复制到当前目录 cp ~/perf.data ./ perf script | ./stackcollapse-perf.pl > out.perf-folded ./flamegraph.pl out.perf-folded > perf-kernel.svg
前往更多细节和其它采样工具。
在 Clojure 程序里使用
使用clj-async-profiler可以在Clojure程序里调用async-profiler
,可以很方便地对特定代码块进行取样分析。