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