FlameGraph
火焰圖 ,簡單通過x軸橫條寬度來度量時間指標(biāo),y軸代表線程棧的層次,簡單明了, 容易找出具體的可有化點,非常方便,當(dāng)然前提是我們通過profiler工具獲取到profiler 數(shù)據(jù)。
java profiler
java性能調(diào)優(yōu)時,我們經(jīng)常會用到profiler工具,但是很多時候你可能不知道,大部分的 profiler工具都是有問題的 , ,簡單來說,profiler:增加開銷;修改了你的 代碼,導(dǎo)致java編譯器的優(yōu)化行為不確定;同時影響了代碼的層次,層次越深自然也影響 執(zhí)行效率。
當(dāng)然如果你不是通過上面方式實現(xiàn),二是通過獲取on-cpu線程的線程棧方式,這又會帶來 一個麻煩的問題:獲取系統(tǒng)范圍的線程棧,jvm必須處于safepoint 狀態(tài),只有當(dāng)線 程處于safepoint狀態(tài)的時候,別的線程才能去獲取它的線程棧,而這個safepoint是由jvm 控制的,這對于profiler非常不利,有可能一個很熱的代碼塊,jvm不會在該代碼塊中間放 置safepoint,導(dǎo)致profiler無法獲得該線程棧,導(dǎo)致錯誤的profiler結(jié)果。
上面的問題幾個商用的profiler工具都存在,Oracle Solaris studio利用的是jvmti的一 個非標(biāo)準(zhǔn)接口AsyncGetCallTrace來實現(xiàn),不存在上面問題,Jeremy Manson也利用該接口 實現(xiàn)了一個簡單的profiler工具: Lightweight Asynchronous Sampling Profiler ,我們 的火焰圖的數(shù)據(jù)來源就是通過它來獲取的。
lightweight-java-profiler
當(dāng)然,這個工具只支持hotspot的vm,需要你自己編譯,有些問題需要注意:
- 如果你需要在rhel上編譯,需要安裝4.6以上版本gcc ,4.4版本不支持。
- 如果你需要在ubunt上編譯,可能會碰到編譯錯誤 。
編譯的時候,需要主要修改BITS參數(shù),如果你要編譯64Bit,使用命令:
make BITS=64 all
使用方法很簡單,直接在你的啟動命令上添加如下參數(shù):
-agentpath:path/to/liblagent.so[:file=name]
啟動之后,會在啟動目錄下生成trace.txt文件(缺?。撐募褪俏覀冃枰牟蓸訑?shù)據(jù)。
另外有幾個參數(shù)可在編譯時修改,都在global.h文件中。首先是采樣的頻率,缺省是100次 每秒;另外是最大采樣的線程棧,缺省3000,超過3000就忽略(對于復(fù)雜的應(yīng)用明顯不夠) ;最后是棧的深度,缺省是128(對于調(diào)用層次深的應(yīng)用調(diào)大)。當(dāng)然你記錄的東西越多, 也會有性能損耗,我調(diào)成30000+256,一刻鐘生成200M文件。
另外特別需要注意,trace不是實時寫入,而是在應(yīng)用shutdown的時候才寫入的,別kill應(yīng) 用,否則trace里面什么都沒有。