使用火焰图分析系统资源使用情况

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,可以很方便地对特定代码块进行取样分析。

参考