上週一個偶然的機會聽同事提到了Java FlameGraph,剛實驗了一下,效果很是好。html
1、什麼是FlameGraphjava
直接看圖說話。FlameGraph 是 SVG格式,矢量圖,能夠隨意擴大縮小,看不清的信息能夠放大看。圖中,各類紅橙黃色沒有什麼意義,僅僅作區分用;x軸橫條寬度來度量時間指標,代表每一個接口實際佔用的CPU時間;y軸表明線程棧的層次,從最底下往上表示堆棧的層層調用。經過看圖,能夠發現哪一個接口占用的CPU時間較多,從而優化;同時,能夠發現調用關係。git
Java火焰圖的做者是Brendan Gregg,他的博客很是有意思,不少關於性能的分析。如下連接是對每一個類別的火焰圖的詳細說明。github
什麼是Java Flame Graphs:Java Flame Graphs瀏覽器
On-CPU:CPU Flame Graphsjvm
Off-CPU:Off-CPU Flame Graphside
Memory:Memory Leak (and Growth) Flame Graphssvg
Hot/Cold:Hot/Cold Flame Graphs函數
Differential:Differential Flame Graphs工具
關於火焰圖的PPT(講解得很是詳細):Blazing Performance with Flame Graphs
2、如何生成
兩個步驟: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)轉換
幾個商用的profiler工具都存在上述問題。可是,Oracle Solaris studio利用的是jvmti的一個非標準接口AsyncGetCallTrace來實現,不存在上面問題,Jeremy Manson也利用該接口 實現了一個簡單的profiler工具:lightweight-java-profiler。