Java 应用在线性能分析和火焰图

在碰到线上性能问题的时候,如果能在线通过采样方式获取热点函数/方法就可以更方便地定位问题所在,进行优化。采用在线采样的方式,由于性能影响小,可以比较放心地在线上进行,获取第一手数据。Linux 平台上,对于多数 C/C++ 编写的应用,可以通过 perf 来方便的采样,还可以进一步生成火焰图来更直观地观察。Java 是没法直接用 perf 的。虽然有一个 perf-map-agent,但是并不方便,尝试过程中还弄出了 kernel panic,所以这玩意是不敢在线上用了。不过 JDK 自己其实已经带了一个采样工具 FlightRecorder ,算是 JMC 的一部分。在 Java 11 以及之后版本的 OpenJDK 中以及可以随意使用。但是在之前版本中,是只有 Oracle JDK 才有的,还算商业版本的功能,虽说启用的时候并没检查 license,但是理论上要在生产环境用,还是要花钱的。

首先,应用启动的时候,要给 java 加上参数:

-XX:+UnlockCommercialFeatures -XX:+FlightRecorder -XX:FlightRecorderOptions=loglevel=info

因为 JVM 默认在 safepoint 的地方才可以返回栈,所以最好加上

-XX:+UnlockDiagnosticVMOptions -XX:+DebugNonSafepoints

让 JVM 在非 safepoint 的时候也提供原数据。

然后在想开始采样的时候

sudo -u <java_user> -i jcmd <pid> JFR.start filename=/tmp/app.jfr duration=60s  settings=profile

这里可以指定输出的文件路径,和采样时间。之后可以用

sudo -u <java_user> -i jcmd <pid> JFR.check

来检查采样是不是已经完成了。

此处的 settings=profile 会增加一些性能指标的采样,比如堆内对象,IO 等。默认是 default。这里的 profile、default 实际是配置文件名,位于 $JAVA_HOME/jre/lib/jfr 下。也可以创建自己的配置。

更详细的用法可以参考官方文档:https://docs.oracle.com/javacomponents/jmc-5-4/jfr-runtime-guide/toc.htm

确认完成后,就可以把 jfr 文件传回本地,用 jmc 来分析了。如果想要生成火焰图,还有这么个工具:https://github.com/chrishantha/jfr-flame-graph。具体用法可以看文档。大致上,代码拖回来后,

cd jfr-flame-graph
install-mc-jars.sh
mvn clean install -U

就编译好了。另外还需要 https://github.com/brendangregg/FlameGraph

工具准备好以后,

path/to/jfr-flame-graph/run.sh -f app.jfr -o app.txt
cat app.txt | path/to/FlameGraph/flamegraph.pl >app.svg

就能生成一个漂亮的火焰图了。

参考链接

  1. https://docs.oracle.com/javacomponents/jmc-5-5/jfr-command-reference/JFRCR.pdf
  2. https://docs.oracle.com/javacomponents/jmc-5-5/jfr-command-reference/diagnostic-command-reference.htm

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s