簡介:java
Eclipse Memory Analyzer(MAT)是著名的跨平臺集成開發環境 Eclipse Galileo 版本的 33 個組成項目中之一,它是一個功能豐富的 JAVA 堆轉儲文件分析工具,能夠幫助你發現內存漏洞和減小內存消耗。本文主要介紹如何安裝配置 Memory Analyzer,並結合一個實例,介紹如何利用 MAT 來進行堆轉儲文件分析,找到內存泄露的根源。瀏覽器
概述eclipse
對於大型 JAVA 應用程序來講,再精細的測試也難以堵住全部的漏洞,即使咱們在測試階段進行了大量卓有成效的工做,不少問題仍是會在生產環境下暴露出來,而且很難在測試環 境中進行重現。JVM 可以記錄下問題發生時系統的部分運行狀態,並將其存儲在堆轉儲 (Heap Dump) 文件中,從而爲咱們分析和診斷問題提供了重要的依據。工具
一般內存泄露分析被認爲是一件頗有難度的工做,通常由團隊中的資深人士進行。不過,今天咱們要介紹的 MAT(Eclipse Memory Analyzer)被認爲是一個「傻瓜式「的堆轉儲文件分析工具,你只須要輕輕點擊一下鼠標就能夠生成一個專業的分析報告。和其餘內存泄露分析工具相 比,MAT 的使用很是容易,基本能夠實現一鍵到位,即便是新手也可以很快上手使用。測試
MAT 的使用是如此容易,你是否是也頗有興趣來親自感覺下呢,那麼第一步咱們先來安裝 MAT。.net
在eclipse安插件的地址以下,不解釋
http://download.eclipse.org/mat/1.2/update-site/插件
Vm參數:線程
-verbose:gc -Xms20M -Xmx20M -Xmn10M -XX:+PrintGCDetails -XX:SurvivorRatio=8 -XX:+HeapDumpOnOutOfMemoryError對象
首先,啓動前面安裝配置好的 Memory Analyzer tool , 而後選擇菜單項 File- Open Heap Dump 來加載須要分析的堆轉儲文件。文件加載完成後,你能夠看到如圖 4 所示的界面:
經過上面的概覽,咱們對內存佔用狀況有了一個整體的瞭解。先檢查一下 MAT 生成的一系列文件。
能夠看到 MAT 工具提供了一個很貼心的功能,將報告的內容壓縮打包到一個 zip 文件,並把它存放到原始堆轉儲文件的存放目錄下,這樣若是您須要和同事一塊兒分析這個內存問題的話,只須要把這個小小的 zip 包發給他就能夠了,不須要把整個堆文件發給他。而且整個報告是一個 HTML 格式的文件,用瀏覽器就能夠輕鬆打開。
接下來咱們就能夠來看看生成的報告都包括什麼內容,能不能幫咱們找到問題所在吧。您能夠點擊工具欄上的 Leak Suspects 菜單項來生成內存泄露分析報告,也能夠直接點擊餅圖下方的 Reports->Leak Suspects 連接來生成報告。
一般咱們都會採用下面的「三步曲」來分析內存泄露問題:
首先,對問題發生時刻的系統內存狀態獲取一個總體印象。
第二步,找到最有可能致使內存泄露的元兇,一般也就是消耗內存最多的對象
接下來,進一步去查看這個內存消耗大戶的具體狀況,看看是否有什麼異常的行爲。
下面將用一個基本的例子來展現如何採用「三步曲」來查看生產的分析報告。
如圖 7 所示,在報告上最醒目的就是一張簡潔明瞭的餅圖,從圖上咱們能夠清晰地看到一個可疑對象消耗了系統 99% 的內存。
在圖的下方還有對這個可疑對象的進一步描述。咱們能夠看到內存是由 java.util.Vector 的實例消耗的,com.ibm.oti.vm.BootstrapClassLoader 負責這個對象的加載。這段描述很是短,但我相信您已經能夠從中找到不少線索了,好比是哪一個類佔用了絕大多數的內存,它屬於哪一個組件等等。
接下來,咱們應該進一步去分析問題,爲何一個 Vector 會佔據了系統 99% 的內存,誰阻止了垃圾回收機制對它的回收。
首先咱們簡單回顧下 JAVA 的內存回收機制,內存空間中垃圾回收的工做由垃圾回收器 (Garbage Collector,GC) 完成的,它的核心思想是:對虛擬機可用內存空間,即堆空間中的對象進行識別,若是對象正在被引用,那麼稱其爲存活對象,反之,若是對象再也不被引用,則爲垃 圾對象,能夠回收其佔據的空間,用於再分配。
在垃圾回收機制中有一組元素被稱爲根元素集合,它們是一組被虛擬機直接引用的對象,好比,正在運行的線程對象,系統調用棧裏面的對象以及被 system class loader 所加載的那些對象。堆空間中的每一個對象都是由一個根元素爲起點被層層調用的。所以,一個對象還被某一個存活的根元素所引用,就會被認爲是存活對象,不能被 回收,進行內存釋放。所以,咱們能夠經過分析一個對象到根元素的引用路徑來分析爲何該對象不能被順利回收。若是說一個對象已經不被任何程序邏輯所須要但 是還存在被根元素引用的狀況,咱們能夠說這裏存在內存泄露。
如今,讓咱們開始真正的尋找內存泄露之旅,點擊「Details 」連接,能夠看到如圖 8 所示對可疑對象 1 的詳細分析報告。
咱們能夠很清楚的看到整個引用鏈,內存匯集點是一個擁有大量對象的集合,若是你對代碼比較熟悉的話,相信這些信息應該能給你提供一些找到內存泄露的思路了。
接下來,咱們再繼續看看,這個對象集合裏到底存放了什麼,爲何會消耗掉如此多的內存。
在這張圖上,咱們能夠清楚的看到,這個對象集合中保存了大量 Person 對象的引用,就是它致使的內存泄露。
至此,咱們已經擁有了足夠的信息去尋找泄露點,回到代碼,咱們發現,是下面的代碼致使了內存泄露 :
while (1<2)
{
Person person = new Person("name","address",i);
v.add(person);
person = null;
}
從上面的例子咱們能夠看到用 MAT 來進行堆轉儲文件分析,尋找內存泄露很是簡單,尤爲是對於新手而言,這是一個很好的輔助分析工具。可是,MAT 絕對不只僅是一個「傻瓜式」內存分析工具,它還提供不少高級功能,好比 MAT 支持用 OQL(Object Query Language)對 heap dump 中的對象進行查詢,支持對線程的分析等,有關這些功能的使用能夠參考 MAT 的幫助文檔。