使用 Eclipse Memory Analyzer 進行堆轉(zhuǎn)儲文件分析
Eclipse Memory Analyzer(MAT)是著名的跨平臺集成開發(fā)環(huán)境 Eclipse Galileo 版本的 33 個組成項目中之一,它是一個功能豐富的 JAVA 堆轉(zhuǎn)儲文件分析工具,可以幫助你發(fā)現(xiàn)內(nèi)存漏洞和減少內(nèi)存消耗。本文主要介紹如何安裝配置 Memory Analyzer,并結(jié)合一個實例,介紹如何利用 MAT 來進行堆轉(zhuǎn)儲文件分析,找到內(nèi)存泄露的根源。
0[圖片上傳中。。。(3)] 評論
仇 璐, 軟件工程師, IBM
楊 曉峰, 軟件工程師, IBM
2010 年 7 月 22 日
[圖片上傳中。。。(5)]在 IBM Bluemix 云平臺上開發(fā)并部署您的下一個應(yīng)用。
開始您的試用
概述
對于大型 JAVA 應(yīng)用程序來說,再精細的測試也難以堵住所有的漏洞,即便我們在測試階段進行了大量卓有成效的工作,很多問題還是會在生產(chǎn)環(huán)境下暴露出來,并且很難在測試環(huán)境中進行重現(xiàn)。JVM 能夠記錄下問題發(fā)生時系統(tǒng)的部分運行狀態(tài),并將其存儲在堆轉(zhuǎn)儲 (Heap Dump) 文件中,從而為我們分析和診斷問題提供了重要的依據(jù)。
通常內(nèi)存泄露分析被認為是一件很有難度的工作,一般由團隊中的資深人士進行。不過,今天我們要介紹的 MAT(Eclipse Memory Analyzer)被認為是一個“傻瓜式“的堆轉(zhuǎn)儲文件分析工具,你只需要輕輕點擊一下鼠標(biāo)就可以生成一個專業(yè)的分析報告。和其他內(nèi)存泄露分析工具相比,MAT 的使用非常容易,基本可以實現(xiàn)一鍵到位,即使是新手也能夠很快上手使用。
MAT 的使用是如此容易,你是不是也很有興趣來親自感受下呢,那么第一步我們先來安裝 MAT。
回頁首
準備環(huán)境和測試數(shù)據(jù)
我們使用的是 Eclipse Memory Analyzer V0.8,Sun JDK 6
安裝 MAT
和其他插件的安裝非常類似,MAT 支持兩種安裝方式,一種是“單機版“的,也就是說用戶不必安裝 Eclipse IDE 環(huán)境,MAT 作為一個獨立的 Eclipse RCP 應(yīng)用運行;另一種是”集成版“的,也就是說 MAT 也可以作為 Eclipse IDE 的一部分,和現(xiàn)有的開發(fā)平臺集成。
集成版的安裝需要借助 Update Manager。
如圖 1 所示,首先通過 Help -> Software Updates... 啟動軟件更新管理向?qū)А?br>
圖 1. 安裝插件第一步

http://download.eclipse.org/mat/1.6.1/update-site/
圖 2. 安裝插件第二步
[圖片上傳中。。。(7)]如圖 3 所示,接下來選擇你想要安裝的 MAT 的功能點,需要注意的是 Memory Analyzer (Chart) 這個功能是一個可選的安裝項目,它主要用來生成相關(guān)的報表,不過如果需要用到這個功能,你還需要額外的安裝 BIRT Chart Engine。
圖 3. 安裝插件第三步
[圖片上傳中。。。(8)]插件安裝完畢,你還需要重新啟動 Eclipse 的工作平臺。
比較而言,單機版的安裝方式非常簡單,用戶只需要下載相應(yīng)的安裝包,然后解壓縮即可運行,這也是被普遍采用的一種安裝方式。在下面的例子里,我們使用的也是單機版的 MAT。具體的下載要求和地址可參見其產(chǎn)品下載頁面:http://www.eclipse.org/mat/downloads.php。
另外,如果你需要用 MAT 來分析 IBM JVM 生成的 dump 文件的話,還需要額外安裝 IBM Diagnostic Tool Framework ,具體的下載和安裝配置步驟請參見:http://www.ibm.com/developerworks/java/jdk/tools/dtfj.html
配置環(huán)境參數(shù)
安裝完成之后,為了更有效率的使用 MAT,我們還需要做一些配置工作。因為通常而言,分析一個堆轉(zhuǎn)儲文件需要消耗很多的堆空間,為了保證分析的效率和性能,在有條件的情況下,我們會建議分配給 MAT 盡可能多的內(nèi)存資源。你可以采用如下兩種方式來分配內(nèi)存更多的內(nèi)存資源給 MAT。
一種是修改啟動參數(shù) MemoryAnalyzer.exe -vmargs -Xmx4g
另一種是編輯文件 MemoryAnalyzer.ini,在里面添加類似信息 -vmargs – Xmx4g。
至此,MAT 就已經(jīng)成功地安裝配置好了,開始進入實戰(zhàn)吧。
獲得堆轉(zhuǎn)儲文件
巧婦難為無米之炊,我們首先需要獲得一個堆轉(zhuǎn)儲文件。為了方便,本文采用的是 Sun JDK 6。通常來說,只要你設(shè)置了如下所示的 JVM 參數(shù):
-XX:+HeapDumpOnOutOfMemoryError
JVM 就會在發(fā)生內(nèi)存泄露時抓拍下當(dāng)時的內(nèi)存狀態(tài),也就是我們想要的堆轉(zhuǎn)儲文件。
如果你不想等到發(fā)生崩潰性的錯誤時才獲得堆轉(zhuǎn)儲文件,也可以通過設(shè)置如下 JVM 參數(shù)來按需獲取堆轉(zhuǎn)儲文件。
-XX:+HeapDumpOnCtrlBreak
除此之外,還有很多的工具,例如 JMap,JConsole 都可以幫助我們得到一個堆轉(zhuǎn)儲文件。本文實例就是使用 JMap 直接獲取了 Eclipse Galileo 進程的堆轉(zhuǎn)儲文件。您可以使用如下命令:
JMap -dump:format=b,file=<dumpfile> <pid>
不過,您需要了解到,不同廠家的 JVM 所生成的堆轉(zhuǎn)儲文件在數(shù)據(jù)存儲格式以及數(shù)據(jù)存儲內(nèi)容上有很多區(qū)別, MAT 不是一個萬能工具,它并不能處理所有類型的堆存儲文件。但是比較主流的廠家和格式,例如 Sun, HP, SAP 所采用的 HPROF 二進制堆存儲文件,以及 IBM 的 PHD 堆存儲文件等都能被很好的解析(您需要安裝額外的插件,請參考 相關(guān)說明,本文不作詳細解釋)。
萬事俱備,接下來,我們就可以開始體驗一鍵式的堆存儲分析功能了。
回頁首
生成分析報告
首先,啟動前面安裝配置好的 Memory Analyzer tool , 然后選擇菜單項 File- Open Heap Dump 來加載需要分析的堆轉(zhuǎn)儲文件。文件加載完成后,你可以看到如圖 4 所示的界面:
圖 4. 概覽
[圖片上傳中。。。(9)]通過上面的概覽,我們對內(nèi)存占用情況有了一個總體的了解。先檢查一下 MAT 生成的一系列文件。
圖 5. 文件列表
[圖片上傳中。。。(10)]可以看到 MAT 工具提供了一個很貼心的功能,將報告的內(nèi)容壓縮打包到一個 zip 文件,并把它存放到原始堆轉(zhuǎn)儲文件的存放目錄下,這樣如果您需要和同事一起分析這個內(nèi)存問題的話,只需要把這個小小的 zip 包發(fā)給他就可以了,不需要把整個堆文件發(fā)給他。并且整個報告是一個 HTML 格式的文件,用瀏覽器就可以輕松打開。
接下來我們就可以來看看生成的報告都包括什么內(nèi)容,能不能幫我們找到問題所在吧。您可以點擊工具欄上的 Leak Suspects 菜單項來生成內(nèi)存泄露分析報告,也可以直接點擊餅圖下方的 Reports->Leak Suspects 鏈接來生成報告。
圖 6. 工具欄菜單
[圖片上傳中。。。(11)]
回頁首
分析三步曲
通常我們都會采用下面的“三步曲”來分析內(nèi)存泄露問題:
首先,對問題發(fā)生時刻的系統(tǒng)內(nèi)存狀態(tài)獲取一個整體印象。
第二步,找到最有可能導(dǎo)致內(nèi)存泄露的元兇,通常也就是消耗內(nèi)存最多的對象
接下來,進一步去查看這個內(nèi)存消耗大戶的具體情況,看看是否有什么異常的行為。
下面將用一個基本的例子來展示如何采用“三步曲”來查看生產(chǎn)的分析報告。
查看報告之一:內(nèi)存消耗的整體狀況
圖 7. 內(nèi)存泄露分析報告
[圖片上傳中。。。(12)]如圖 7 所示,在報告上最醒目的就是一張簡潔明了的餅圖,從圖上我們可以清晰地看到一個可疑對象消耗了系統(tǒng) 99% 的內(nèi)存。
在圖的下方還有對這個可疑對象的進一步描述。我們可以看到內(nèi)存是由 java.util.Vector 的實例消耗的,com.ibm.oti.vm.BootstrapClassLoader 負責(zé)這個對象的加載。這段描述非常短,但我相信您已經(jīng)可以從中找到很多線索了,比如是哪個類占用了絕大多數(shù)的內(nèi)存,它屬于哪個組件等等。
接下來,我們應(yīng)該進一步去分析問題,為什么一個 Vector 會占據(jù)了系統(tǒng) 99% 的內(nèi)存,誰阻止了垃圾回收機制對它的回收。
查看報告之二:分析問題的所在
首先我們簡單回顧下 JAVA 的內(nèi)存回收機制,內(nèi)存空間中垃圾回收的工作由垃圾回收器 (Garbage Collector,GC) 完成的,它的核心思想是:對虛擬機可用內(nèi)存空間,即堆空間中的對象進行識別,如果對象正在被引用,那么稱其為存活對象,反之,如果對象不再被引用,則為垃圾對象,可以回收其占據(jù)的空間,用于再分配。
在垃圾回收機制中有一組元素被稱為根元素集合,它們是一組被虛擬機直接引用的對象,比如,正在運行的線程對象,系統(tǒng)調(diào)用棧里面的對象以及被 system class loader 所加載的那些對象。堆空間中的每個對象都是由一個根元素為起點被層層調(diào)用的。因此,一個對象還被某一個存活的根元素所引用,就會被認為是存活對象,不能被回收,進行內(nèi)存釋放。因此,我們可以通過分析一個對象到根元素的引用路徑來分析為什么該對象不能被順利回收。如果說一個對象已經(jīng)不被任何程序邏輯所需要但是還存在被根元素引用的情況,我們可以說這里存在內(nèi)存泄露。
現(xiàn)在,讓我們開始真正的尋找內(nèi)存泄露之旅,點擊“Details ”鏈接,可以看到如圖 8 所示對可疑對象 1 的詳細分析報告。
圖 8. 可疑對象 1 的詳細分析報告
[圖片上傳中。。。(13)]我們查看下從 GC 根元素到內(nèi)存消耗聚集點的最短路徑:
圖 9. 從根元素到內(nèi)存消耗聚集點的最短路徑
[圖片上傳中。。。(14)]我們可以很清楚的看到整個引用鏈,內(nèi)存聚集點是一個擁有大量對象的集合,如果你對代碼比較熟悉的話,相信這些信息應(yīng)該能給你提供一些找到內(nèi)存泄露的思路了。
接下來,我們再繼續(xù)看看,這個對象集合里到底存放了什么,為什么會消耗掉如此多的內(nèi)存。
圖 10. 內(nèi)存消耗聚集對象信息
[圖片上傳中。。。(15)]在這張圖上,我們可以清楚的看到,這個對象集合中保存了大量 Person 對象的引用,就是它導(dǎo)致的內(nèi)存泄露。
至此,我們已經(jīng)擁有了足夠的信息去尋找泄露點,回到代碼,我們發(fā)現(xiàn),是下面的代碼導(dǎo)致了內(nèi)存泄露 :
清單 1. 內(nèi)存泄漏的代碼段
while (1<2) { Person person = new Person("name","address",i); v.add(person); person = null; }
回頁首
總結(jié)
從上面的例子我們可以看到用 MAT 來進行堆轉(zhuǎn)儲文件分析,尋找內(nèi)存泄露非常簡單,尤其是對于新手而言,這是一個很好的輔助分析工具。但是,MAT 絕對不僅僅是一個“傻瓜式”內(nèi)存分析工具,它還提供很多高級功能,比如 MAT 支持用 OQL(Object Query Language)對 heap dump 中的對象進行查詢,支持對線程的分析等,有關(guān)這些功能的使用可以參考 MAT 的幫助文檔。
參考資料
您可以查看 Eclipse 的 MAT 項目首頁,了解 MAT 的最新動態(tài)。
訪問 developerWorks Open source 專區(qū)獲得豐富的 how-to 信息、工具和項目更新以及 最受歡迎的文章和教程,幫助您用開放源碼技術(shù)進行開發(fā),并將它們與 IBM 產(chǎn)品結(jié)合使用。
條評論
請 登錄 或 注冊 后發(fā)表評論。
添加評論:
注意:評論中不支持 HTML 語法
有新評論時提醒我
剩余 1000 字符
快來添加第一條評論
[圖片上傳中。。。(16)]IBM Bluemix 資源中心
文章、教程、演示,幫助您構(gòu)建、部署和管理云應(yīng)用。
[圖片上傳中。。。(17)]developerWorks 中文社區(qū)
立即加入來自 IBM 的專業(yè) IT 社交網(wǎng)絡(luò)。
[圖片上傳中。。。(18)]IBM 軟件資源中心
免費下載、試用軟件產(chǎn)品,構(gòu)建應(yīng)用并提升技能。
隱私條約
瀏覽輔助
IBM 教育學(xué)院教育培養(yǎng)計劃
IBM 創(chuàng)業(yè)企業(yè)全球扶持計劃
ISV 資源 (英語)
選擇語言:
English
中文
日本語
Русский
Português (Brasil)
Espa?ol
??
[圖片上傳中。。。(19)]
