jvm性能分析工具之-- Eclipse Memory Analyzer tool(MAT)(二)
前言
在本文中,將介紹MAT如何根據heapdump分析泄漏根源。由于測試范例可能過于簡單,很容易找出問題,但我期待借此舉一反三。
一開始不得不說說ClassLoader,本質上,它的工作就是把磁盤上的類文件讀入內存,然后調用Java.lang.ClassLoader.defineClass方法告訴系統把內存鏡像處理成合法的字節碼。Java提供了抽象類ClassLoader,所有用戶自定義類裝載器都實例化自ClassLoader的子類。systemclass loader在沒有指定裝載器的情況下默認裝載用戶類,在Sun Java 1.5中既sun.misc.Launcher$AppClassLoader。更詳細的內容請參看下面的資料。
準備heap dump
請看下面的Pilot類,沒啥特殊的。
/**
?*?Pilot?class
?*?@author?rosen?jiang
?*/
package?org.rosenjiang.bo;
public?class?Pilot{
????
????String?name;
????int?age;
????
????public?Pilot(String?a,?int?b){
????????name?=?a;
????????age?=?b;
????}
}
然后再看OOMHeapTest類,它是如何撐破heapdump的。
/**
?*?OOMHeapTest?class
?*?@author?rosen?jiang
?*/
package?org.rosenjiang.test;
import?java.util.Date;
import?java.util.HashMap;
import?java.util.Map;
import?org.rosenjiang.bo.Pilot;
public?class?OOMHeapTest?{
????public?static?void?main(String[]?args){
????????oom();
????}
????
????private?static?void?oom(){
????????Map<String,?Pilot>?map?=?new?HashMap<String,?Pilot>();
????????Object[]?array?=?new?Object[1000000];
????????for(int?i=0;?i<1000000;?i++){
????????????String?d?=?new?Date().toString();
????????????Pilot?p?=?new?Pilot(d,?i);
????????????map.put(i+"rosen?jiang",?p);
????????????array[i]=p;
????????}
????}
}
是的,上面構造了很多的Pilot類實例,向數組和map中放。由于是StrongRef,GC自然不會回收這些對象,一直放在heap中直到溢出。當然在運行前,先要在Eclipse中配置VM參數-XX:+HeapDumpOnOutOfMemoryError。好了,一會兒功夫內存溢出,控制臺打出如下信息。
java.lang.OutOfMemoryError:?Java?heap?space
Dumping?heap?to?java_pid3600.hprof?
Heap?dump?file?created?[78233961?bytes?in?1.995?secs]
Exception?in?thread?"main"?java.lang.OutOfMemoryError:?Java?heap?space
java_pid3600.hprof既是heap dump,可以在OOMHeapTest類所在的工程根目錄下找到。
?
MAT安裝
話分兩頭說,有了heap dump還得安裝MAT。
MAT支持兩種安裝方式,一種是“獨立版本”,用戶不必安裝?EclipseIDE?環境,MAT?作為一個獨立的?EclipseRCP?應用運行;另一種是“插件版本”,也就是說MAT?可以作為?EclipseIDE?的一個插件,和Eclipse開發平臺集成。
獨立版本,下載地址:http://www.eclipse.org/mat/downloads.php
下載的zip包,解壓即可使用。下載頁圖示如下:
與eclipse IDE集成安裝過程,可參看以下文章:
http://www.ibm.com/developerworks/cn/opensource/os-cn-ecl-ma/index.html
安裝完成后,為了更有效率的使用?MAT,我們可以配置一些環境參數。因為通常而言,分析一個堆轉儲文件需要消耗很多的堆空間,為了保證分析的效率和性能,在有條件的情況下,我們會建議分配給?MAT?盡可能多的內存資源。你可以采用如下兩種方式來分配內存更多的內存資源給?MAT。
一種是修改啟動參數?MemoryAnalyzer.exe-vmargs -Xmx4g
另一種是編輯文件?MemoryAnalyzer.ini,在里面添加類似信息?-vmargs– Xmx4g。
說明:
1. MemoryAnalyzer.ini中的參數一般默認為-vmargs– Xmx1024m,這就夠用了。假如你機器的內存不大,改大該參數的值,會導致MemoryAnalyzer啟動時,報錯:Failed to create the Java Virtual Machine。
2.當你導出的dump文件的大小大于你配置的1024m(說明1中,提到的配置:-vmargs– Xmx1024m),MAT輸出分析報告的時候,會報錯:An internal error occurred during: "Parsing heap dump from XXX”。適當調大說明1中的參數即可。
至此,MAT?就已經成功地安裝配置好了,在Eclipse的左上角有Open Heap Dump按鈕,按照剛才說的路徑找到java_pid3600.hprof文件并打開。
先檢查一下?MAT生成的一系列文件:(截圖來自另一個例子)
可以看到?MAT工具提供了一個很貼心的功能,將報告的內容壓縮打包到一個?zip文件,并把它存放到原始堆轉儲文件的存放目錄下,這樣如果您需要和同事一起分析這個內存問題的話,只需要把這個小小的?zip包發給他就可以了,不需要把整個堆文件發給他。并且整個報告是一個?HTML格式的文件,用瀏覽器就可以輕松打開。
使用MAT打開dump文件,等待一會后,會彈出向導界面,保持默認設置,直接點Finish即是分析內存泄露問題。在點擊Finish后,會出現overview界面,您可以點擊工具欄上的?Leak Suspects?菜單項來生成內存泄露分析報告,也可以直接點擊餅圖下方的?Reports->Leak Suspects鏈接來生成報告。如圖:
MAT工具分析了heap dump后在界面上非常直觀的展示了一個餅圖,該圖深色區域被懷疑有內存泄漏,可以發現整個heap才64M內存,深色區域就占了99.5%。接下來是一個簡短的描述,告訴我們main線程占用了大量內存,并且明確指出system class loader加載的"java.lang.Thread"實例有內存聚集,并建議用關鍵字"java.lang.Thread"進行檢查。所以,MAT通過簡單的兩句話就說明了問題所在,就算使用者沒什么處理內存問題的經驗。在下面還有一個"Details"鏈接,在點開之前不妨考慮一個問題:為何對象實例會聚集在內存中,為何存活(而未被GC)?是的——Strong Ref,那么再走近一些吧。如圖:
點擊了"Details"鏈接之后,除了在上一頁看到的描述外,還有Shortest Paths To the Accumulation Point和Accumulated Objects部分,這里說明了從GC root到聚集點的最短路徑,以及完整的reference chain。觀察Accumulated Objects部分,java.util.HashMap和java.lang.Object[1000000]實例的retained heap(size)最大,在上一篇文章中我們知道retained heap代表從該類實例沿著reference chain往下所能收集到的其他類實例的shallow heap(size)總和,所以明顯類實例都聚集在HashMap和Object數組中了。這里我們發現一個有趣的現象,既Object數組的shallow heap和retained heap竟然一樣,通過Shallow and retained sizes一文可知,數組的shallow heap和一般對象(非數組)不同,依賴于數組的長度和里面的元素的類型,對數組求shallow heap,也就是求數組集合內所有對象的shallow heap之和。好,再來看org.rosenjiang.bo.Pilot對象實例的shallow heap為何是16,因為對象頭是8字節,成員變量int是4字節、String引用是4字節,故總共16字節。
在Accumulated Objects視圖中,retained heap占用最多的是hashMap和object數組,為啥它們會占用這么大的heap呢?這個時候需要分析hashMap和object數組中存放了一些什么對象?接著往下看,來到了Accumulated Objects by Class區域,顧名思義,這里能找到被聚集的對象實例的類名。org.rosenjiang.bo.Pilot類上頭條了,被實例化了290,325次,再返回去看程序,我承認是故意這么干的。還有很多有用的報告可用來協助分析問題,只是本文中的例子太簡單,也用不上。
為了更多的了解MAT的功能,再舉一些例子(不提供對應的代碼):
例子二:
通過MAT發現heap dump問題所在,就需要尋找導致內存泄漏的代碼點。這時往往需要打開對象依賴關系樹形視圖,點擊如圖按鈕即可。?
這時會看到如下視圖:
這個視圖的右邊大區域可以看到對象的依賴關系,選中某個對象以后可以在左邊小窗口查看對象的一些屬性。如果屬性的值是一些內存地址你還可以點擊工具欄的搜索按鈕來搜索具體的對象信息。在進行具體分析的時候MAT只是起了幫助你進行分析的工具的功能,OOM問題分析沒有固定方法和準則。只能發揮你敏銳的洞察力,結合源代碼,對內存中的對象進行分析從而找到代碼中的BUG.?
例子三:
如何查看某一個對象占用的內存空間?
1.按以下方式打開新窗口即可?,如圖:
2.輸入類名(輸入類的全名)?,如圖:
總結
以上是生活随笔為你收集整理的jvm性能分析工具之-- Eclipse Memory Analyzer tool(MAT)(二)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: BO6.5和DIXI的安装和部署
- 下一篇: 最简单的基于FFMPEG+SDL的音频播