Java FlameGraph 火焰图

上周一个偶然的机会听同事提到了Java FlameGraph,刚实验了一下,效果非常好。

一、什么是FlameGraph

直接看图说话。FlameGraph 是 SVG格式,矢量图,可以随意扩大缩小,看不清的信息可以放大看。图中,各种红橙黄色没有什么意义,仅仅做区分用;x轴横条宽度来度量时间指标,表明每个接口实际占用的CPU时间;y轴代表线程栈的层次,从最底下往上表示堆栈的层层调用。通过看图,可以发现哪个接口占用的CPU时间较多,从而优化;同时,可以发现调用关系。

 

Java火焰图的作者是Brendan Gregg,他的博客非常有意思,很多关于性能的分析。以下链接是对每个类别的火焰图的详细说明。

什么是Java Flame Graphs:Java Flame Graphs

On-CPU:CPU Flame Graphs

Off-CPU:Off-CPU Flame Graphs

Memory:Memory Leak (and Growth) Flame Graphs

Hot/Cold:Hot/Cold Flame Graphs

Differential:Differential Flame Graphs

关于火焰图的PPT(讲解得非常详细):Blazing Performance with Flame Graphs

 

二、如何生成

两个步骤:1. 需要java profiler生成trace文件  2. 将trace文件转换为svg格式的火焰图文件。

1. 需要java profiler生成trace文件

在使用Profiler对CPU进行采样时,根据CPU当前执行所处栈位置以及各个函数栈在总的采样次数所占比例就可以得出各个函数执行时的CPU占用比例。常用的是lightweight-java-profiler。还有其他的选择,比如honest-profiler,lightweight-java-profiler会从java虚拟机启动开始采样,而有时候我们需要在CPU飙高的时候开始,这时候honest-profiler提供的动态启停功能就有用武之地了。也有使用perf生成火焰图。(*perf 要研究一下)

下面以lightweight-java-profiler 举例

(1) 从github下载软件

(2) 编译 make all

(3) 生成的程序存放在build-64文件夹下面

(4)(可选)可以更改一些lightweight-java-profiler的一些选项,打开src/globals.h文件。在长时间采样时,可以适当地减少每秒采样次数,不然最终生成的文件会很大,分析起来比较麻烦。

// 每秒采样频率
static const int kNumInterrupts = 100;
// Maximum number of stack traces线程栈个数
static const int kMaxStackTraces = 3000;
// 采样栈深度
static const int kMaxFramesToCapture = 128;  

  kNumInterrupts: 每秒钟抽取样本的次数;

  kMaxStackTraces: 线程栈的最大数量   

  kMaxFramesToCapture: 线程栈的深度

 

(5)运行Java程序

  java -agentpath:path/to/liblagent.so ......

(6)java程序启动后会在当前目录生成一个traces.txt文件,但文件中只有一些说明信息。程序正常结束(不杀掉进程)后,才会写入具体采样信息。

 

2.将trace文件转换为svg格式的火焰图文件。

(1)从github下载FlameGraph

(2)转换 

  ./stackcollapse-ljp.awk < traces.txt | ./flamegraph.pl > traces.svg
(3)浏览器中打开traces.svg文件
 
 
 
三、简单讨论一下Java profiler
 
关于采样工具的选取,可以看看文章 Evaluating the Accuracy of Java Profilers ,这里面列举了xprof,hprof,jprofile和yourkit四种采样器,并通过几个压测场景证明了这几种采样器的结果是相互矛盾的。总结的原因有两点:
1. 采样器采样点不够随机,这几种采样器都只有在safe point采样;
2. 不同的采样器会注入不同的代码,从而影响程序优化过程,同时也影响了safe point的分布,进一步造成采样差异;
honest-profiler号称是避开了通过SUN/Oracle management agent去采样堆栈,而是使用自己实现的使用UNIX 操作系统信号和为Oracle Performance Studio 设计的内部API的sampling agent,从而提升了采样准确率。
 
还有一篇文章和 Why many profilers have serous problems。
 
Java profiler 的两个常见方式:
1.修改代码,从而实现采样。问题是:1. 增加开销;2. 修改了你的代码,导致java编译器的优化行为不确定;3. 影响了代码的层次,层次越深自然也影响 执行效率。
2.通过获取on-cpu线程的线程栈方式。问题是:获取系统范围的线程栈,jvm必须处于safepoint状态(看文章What is Java safepoint)。只有当线程处于safepoint状态的时候,别的线程才能去获取它的线程栈,而这个safepoint是由jvm 控制的,这对于profiler非常不利,有可能一个很热的代码块,jvm不会在该代码块中间放置safepoint,导致profiler无法获得该线程栈,导致错误的profiler结果。

几个商用的profiler工具都存在上述问题。但是,Oracle Solaris studio利用的是jvmti的一个非标准接口AsyncGetCallTrace来实现,不存在上面问题,Jeremy Manson也利用该接口 实现了一个简单的profiler工具:lightweight-java-profiler。

 

 
 
 
相关知识:
 部分内容摘自 http://blog.csdn.net/c395318621/article/details/55224665
 部分内容摘自 http://tacy.github.io/blog/2014/07/16/FlameGraph/
 部分内容摘自 http://www.javashuo.com/content/p-6579579.html
 部分内容摘自 http://colobu.com/2016/08/10/Java-Flame-Graphs/
 文章: Evaluating the Accuracy of Java Profilers  
 文章: Why many profilers have serous problems。
 文章: What is Java safepoint
 

 

 

 

转载于:https://www.cnblogs.com/xingzifei/p/7446264.html

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值