java profiler

 几款java性能分析器的使用:

hprof

这是一个基于命令行的调试工具,基于JVMTI实现,可用于cpu使用分析,堆分配统计和竞争监视器分析。此外,它还可以导出完整的堆信息,所有监视器的状态和jvm里的线程信息。

hprof可以这样启动:

java -agentlib:hprof=cpu=samples,depth=100,interval=20,lineno=y,thread=y,file=out.hprof myclass

也可以这样:

java -Xrunhprof[:options] ToBeProfiledClass

分析器会在进程启动时运行,一直到程序退出或者进程收到一个SIGOUIT信号。

分析器会对程序运行栈进行采样,统计所有处于running状态的线程,累计这些活跃的堆栈的轨迹,这样累计数量最多的就很可能是cpu使用热点的堆栈。在上面的示例中,采样的栈深度为最大100层,每20ms采样一次,输出的结果文件为:out.hprof,结果内容包括了调用栈的列表和每个栈的累计调用计数。示例如下:

TRACE 301130: (thread=200001)
	sun.security.ssl.SSLSocketFactoryImpl.createSocket(SSLSocketFactoryImpl.java:72)
	javax.net.ssl.SSLContextSpi.getDefaultSocket(SSLContextSpi.java:143)
	javax.net.ssl.SSLContextSpi.engineGetDefaultSSLParameters(SSLContextSpi.java:168)
	javax.net.ssl.SSLContext.getDefaultSSLParameters(SSLContext.java:419)
	com.netease.hmail.server.netty.NettyServer.prepare(NettyServer.java:503)
	com.netease.hmail.server.launcher.HmailLauncher.prepare(HmailLauncher.java:588)
	com.netease.hmail.server.launcher.HmailLauncher.main(HmailLauncher.java:415)
TRACE 301159: (thread=200001)
	com.netease.hmail.server.launcher.HmailLauncher.prepare(HmailLauncher.java:591)
	com.netease.hmail.server.launcher.HmailLauncher.main(HmailLauncher.java:415)
CPU SAMPLES BEGIN (total = 69) Sat Mar 16 11:17:11 2019
rank   self  accum   count trace method
   1  5.80%  5.80%       4 301179 java.net.SocketInputStream.socketRead0
   2  4.35% 10.14%       3 300841 java.lang.ClassLoader$NativeLibrary.load
   3  2.90% 13.04%       2 300901 java.io.BufferedInputStream.<init>
   4  1.45% 14.49%       1 300024 java.lang.System.arraycopy

这款分析器有个缺点导致它不是很靠谱:hprof在采用java的线程运行状态时,是通过state==JVMTI_THREAD_STATE_RUNNABLE来判断线程是否在占用cpu的,但是runnable状态实际上并不表示线程正在运行,它只表示线程是活跃的,可运行的,它是jvm意义上的runnable,跟操作系统内核调度器的"runnable"并不是同一个含义。所以hprof误以为这些线程在占用大量cpu而实际上cpu可能很空闲,所以根据hprof得到的结果可能不准确,这点要注意。

hprof还有另一个问题是它只在安全点(safepoings)时才进行采样,这样就不是在设置的时间间隔进行采样了,所以hprof是不太可靠的。

 

perf + perf-map-agent + FlameGraph

perf是linux系统级别的分析调试工具,它可以分析程序的各个调用链对cpu的使用进行采样,从而分析出哪个调用消耗的cpu最多。 perf的使用示例如下:

perf record -F 99 -p 13204 -g -- sleep 30
perf report -n --stdio

perf record命令将每秒采样99次(-F 99),目标进程id为13204(-p 13204),同时将采集程序调用栈(-g)。采样的结果可以解析成火焰图,这样看起来会更加直观,解析火焰图可以用FlameGraph,该工具可以从github上下载:

# git clone https://github.com/brendangregg/FlameGraph  # or download it from github
# cd FlameGraph
# perf record -F 99 -a -g -- sleep 60
# perf script | ./stackcollapse-perf.pl > out.perf-folded
# ./flamegraph.pl out.perf-folded > perf-kernel.svg

 perf的采样对于java程序有个问题:它不能识别java堆栈里的方法路径名称,只能以十六进制方式来表示,所以需要一个java符号转换表与perf进行结合来对java程序进行采样分析,这就是perf-map-agent所做的事。

perf-map-agent

  这是一个JVMTI agent,它会为perf提供一份java符号表供转换用,另外,需要在jvm启动参数中加上:  -XX:+PreserveFramePointer ,这样perf才能准确采样。

安装和使用perf-map-agent:

sudo bash
apt-get install cmake
export JAVA_HOME=/path-to-your-new-jdk8
cd /destination-for-perf-map-agent	
git clone --depth=1 https://github.com/jvm-profiling-tools/perf-map-agent
cd perf-map-agent
cmake .
make

 perf-map-agent如果要使用生成火焰图的脚本需要依赖FlameGraph:

git clone --depth=1 https://github.com/brendangregg/FlameGraph

编译后就可以使用bin目录下的工具进行调试分析了,工具说明如下:

  • create-java-perf-map.sh <pid> <options*> takes a PID and options. It knows where to find libraries relative to the bindirectory.
  • perf-java-top <pid> <perf-top-options> takes a PID and additional options to pass to perf top. Uses the agent to create a new /tmp/perf-<pid>.map and then calls perf top with the given options.
  • perf-java-record-stack <pid> <perf-record-options> takes a PID and additional options to pass to perf record. Runsperf record -g -p <pid> <perf-record-options> to collect performance data including stack traces. Afterwards it uses the agent to create a new /tmp/perf-<pid>.map file.
  • perf-java-report-stack <pid> <perf-record-options> calls first perf-java-record-stack <pid> <perf-record-options>and then runs perf report to directly analyze the captured data. You can call perf report -i /tmp/perf-<pid>.dataagain with any options after the script has exited to further analyze the data from the previous run.
  • perf-java-flames <pid> <perf-record-options> collects data with perf-java-record-stack and then creates a visualization using @brendangregg's FlameGraph tools. To get meaningful stacktraces spanning several JIT-compiled methods, you need to run your JVM with -XX:+PreserveFramePointer (which is available starting from JDK8 update 60 build 19) as detailed in ag netflix blog entry.
  • create-links-in <targetdir> will install symbolic links to the above scripts into <targetdir>.
  • dtrace-java-record-stack <pid> takes a PID. Runsdtrace to collect performance data including stack traces. Afterwards it uses the agent to create a new /tmp/perf-<pid>.map file.
  • dtrace-java-flames <pid> collects data with dtrace-java-record-stack and then creates a visualization using @brendangregg's FlameGraph tools. To get meaningful stacktraces spanning several JIT-compiled methods, you need to run your JVM with -XX:+PreserveFramePointer (which is available starting from JDK8 update 60 build 19) as detailed in ag netflix blog entry.

编译后会生成 attach-main.jarlibperfmap.so两个文件,这是获取java程序运行时符号表的关键,而FlameGraph下面的jmaps脚本正是依赖于perf-map-agent来生成火焰图所需要的java符号表,所以perf-map-agent和FlameGraph可以说是相互依赖,查看一下两者的脚本就明白了。

下面的步骤可以生成火焰图:

git clone --depth=1 https://github.com/brendangregg/FlameGraph
sudo bash
perf record -F 49 -a -g -- sleep 30; ./FlameGraph/jmaps
perf script > out.stacks01
cat out.stacks01 | ./FlameGraph/stackcollapse-perf.pl | grep -v cpu_idle | \
    ./FlameGraph/flamegraph.pl --color=java --hash > out.stacks01.svg

也可以直接使用perf-java-map下面的脚本:

sudo ./bin/perf-java-flames 29685

注意:在使用这些脚时,需要修改一下脚本里所依赖的项目目录,如perf命令的名称和路径,FlameGraph的目录等。

async-profiler

同样是基于jvmti来开发的,下载地址如下:

git clone https://github.com/jvm-profiling-tools/async-profiler

需要编译一下:

cd async-profiler
make

 编译后的脚本放在build目录下,进行分析的脚本是:profile.sh,启动采集命令:

./profiler.sh start $pid

 停止采集:

./profiler.sh stop $pid

停止采集后会打印采集的结果。但是这样输出的结果比较简单,也没有产生火焰图,可以使用以下命令来执行采集任务并生成火焰图:

./profiler.sh -d 10 -o collapsed -f /tmp/collapsed.txt pid
./FlameGraph/flamegraph.pl --colors=java /tmp/collapsed.txt > flamegraph.svg

上面的含义是采集任务执行10秒种,并按collapsed格式输出到文件中,这样火焰图工具就可以通过解析这种格式来生成火焰图了。

【参考文献】

http://www.brendangregg.com/blog/2014-06-09/java-cpu-sampling-using-hprof.html

https://docs.oracle.com/javase/7/docs/technotes/samples/hprof.html

http://www.brendangregg.com/FlameGraphs/cpuflamegraphs.html

 

转载于:https://my.oschina.net/u/150599/blog/3023394

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值