程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> 使用Eclipse Memory Analyzer進行堆轉儲文件分析

使用Eclipse Memory Analyzer進行堆轉儲文件分析

編輯:關於JAVA

簡介: Eclipse Memory Analyzer(MAT)是著名的跨平台集成開發環境 Eclipse Galileo 版本的 33 個組成項目中之一,它是一個功能豐富的 JAVA 堆 轉儲文件分析工具,可以幫助你發現內存漏洞和減少內存消耗。本文主要介紹如 何安裝配置 Memory Analyzer,並結合一個實例,介紹如何利用 MAT 來進行堆轉 儲文件分析,找到內存洩露的根源。

概述

對於大型 JAVA 應用程序來說,再精細的測試也難以堵住所有的漏洞,即便我 們在測試階段進行了大量卓有成效的工作,很多問題還是會在生產環境下暴露出 來,並且很難在測試環境中進行重現。JVM 能夠記錄下問題發生時系統的部分運 行狀態,並將其存儲在堆轉儲 (Heap Dump) 文件中,從而為我們分析和診斷問題 提供了重要的依據。

通常內存洩露分析被認為是一件很有難度的工作,一般由團隊中的資深人士進 行。不過,今天我們要介紹的 MAT(Eclipse Memory Analyzer)被認為是一個“ 傻瓜式“的堆轉儲文件分析工具,你只需要輕輕點擊一下鼠標就可以生成一個專 業的分析報告。和其他內存洩露分析工具相比,MAT 的使用非常容易,基本可以 實現一鍵到位,即使是新手也能夠很快上手使用。

MAT 的使用是如此容易,你是不是也很有興趣來親自感受下呢,那麼第一步我 們先來安裝 MAT。

准備環境和測試數據

我們使用的是 Eclipse Memory Analyzer V0.8,Sun JDK 6

安裝 MAT

和其他插件的安裝非常類似,MAT 支持兩種安裝方式,一種是“單機版“的, 也就是說用戶不必安裝 Eclipse IDE 環境,MAT 作為一個獨立的 Eclipse RCP 應用運行;另一種是”集成版“的,也就是說 MAT 也可以作為 Eclipse IDE 的 一部分,和現有的開發平台集成。

集成版的安裝需要借助 Update Manager。

如圖 1 所示,首先通過 Help -> Software Updates... 啟動軟件更新管 理向導。

圖 1. 安裝插件第一步

選擇“Available Software“然後按如圖 2 所示的方式添加 MAT 的更新地址 http://download.eclipse.org/technology/mat/0.8/update-site/。

圖 2. 安裝插件第二步

如圖 3 所示,接下來選擇你想要安裝的 MAT 的功能點,需要注意的是 Memory Analyzer (Chart) 這個功能是一個可選的安裝項目,它主要用來生成相 關的報表,不過如果需要用到這個功能,你還需要額外的安裝 BIRT Chart Engine。

圖 3. 安裝插件第三步

插件安裝完畢,你還需要重新啟動 Eclipse 的工作平台。

比較而言,單機版的安裝方式非常簡單,用戶只需要下載相應的安裝包,然後 解壓縮即可運行,這也是被普遍采用的一種安裝方式。在下面的例子裡,我們使 用的也是單機版的 MAT。具體的下載要求和地址可參見其產品下載頁面: 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

配置環境參數

安裝完成之後,為了更有效率的使用 MAT,我們還需要做一些配置工作。因為 通常而言,分析一個堆轉儲文件需要消耗很多的堆空間,為了保證分析的效率和 性能,在有條件的情況下,我們會建議分配給 MAT 盡可能多的內存資源。你可以 采用如下兩種方式來分配內存更多的內存資源給 MAT。

一種是修改啟動參數 MemoryAnalyzer.exe -vmargs -Xmx4g

另一種是編輯文件 MemoryAnalyzer.ini,在裡面添加類似信息 -vmargs – Xmx4g。

至此,MAT 就已經成功地安裝配置好了,開始進入實戰吧。

獲得堆轉儲文件

巧婦難為無米之炊,我們首先需要獲得一個堆轉儲文件。為了方便,本文采用 的是 Sun JDK 6。通常來說,只要你設置了如下所示的 JVM 參數:

-XX:+HeapDumpOnOutOfMemoryError

JVM 就會在發生內存洩露時抓拍下當時的內存狀態,也就是我們想要的堆轉儲 文件。

如果你不想等到發生崩潰性的錯誤時才獲得堆轉儲文件,也可以通過設置如下 JVM 參數來按需獲取堆轉儲文件。

-XX:+HeapDumpOnCtrlBreak

除此之外,還有很多的工具,例如 JMap,JConsole 都可以幫助我們得到一個 堆轉儲文件。本文實例就是使用 JMap 直接獲取了 Eclipse Galileo 進程的堆轉 儲文件。您可以使用如下命令:

JMap -dump:format=b,file=<dumpfile> <pid>

不過,您需要了解到,不同廠家的 JVM 所生成的堆轉儲文件在數據存儲格式 以及數據存儲內容上有很多區別, MAT 不是一個萬能工具,它並不能處理所有類 型的堆存儲文件。但是比較主流的廠家和格式,例如 Sun, HP, SAP 所采用的 HPROF 二進制堆存儲文件,以及 IBM 的 PHD 堆存儲文件等都能被很好的解析。

萬事俱備,接下來,我們就可以開始體驗一鍵式的堆存儲分析功能了。

生成分析報告

首先,啟動前面安裝配置好的 Memory Analyzer tool , 然後選擇菜單項 File- Open Heap Dump 來加載需要分析的堆轉儲文件。文件加載完成後,你可以 看到如圖 4 所示的界面:

圖 4. 概覽

通過上面的概覽,我們對內存占用情況有了一個總體的了解。先檢查一下 MAT 生成的一系列文件。

圖 5. 文件列表

可以看到 MAT 工具提供了一個很貼心的功能,將報告的內容壓縮打包到一個 zip 文件,並把它存放到原始堆轉儲文件的存放目錄下,這樣如果您需要和同事 一起分析這個內存問題的話,只需要把這個小小的 zip 包發給他就可以了,不需 要把整個堆文件發給他。並且整個報告是一個 HTML 格式的文件,用浏覽器就可 以輕松打開。

接下來我們就可以來看看生成的報告都包括什麼內容,能不能幫我們找到問題 所在吧。您可以點擊工具欄上的 Leak Suspects 菜單項來生成內存洩露分析報告 ,也可以直接點擊餅圖下方的 Reports->Leak Suspects 鏈接來生成報告。

圖 6. 工具欄菜單

分析三步曲

通常我們都會采用下面的“三步曲”來分析內存洩露問題:

首先,對問題發生時刻的系統內存狀態獲取一個整體印象。

第二步,找到最有可能導致內存洩露的元凶,通常也就是消耗內存最多的對象

接下來,進一步去查看這個內存消耗大戶的具體情況,看看是否有什麼異常的 行為。

下面將用一個基本的例子來展示如何采用“三步曲”來查看生產的分析報告。

查看報告之一:內存消耗的整體狀況

圖 7. 內存洩露分析報告

如圖 7 所示,在報告上最醒目的就是一張簡潔明了的餅圖,從圖上我們可以 清晰地看到一個可疑對象消耗了系統 99% 的內存。

在圖的下方還有對這個可疑對象的進一步描述。我們可以看到內存是由 java.util.Vector 的實例消耗的,com.ibm.oti.vm.BootstrapClassLoader 負責 這個對象的加載。這段描述非常短,但我相信您已經可以從中找到很多線索了, 比如是哪個類占用了絕大多數的內存,它屬於哪個組件等等。

接下來,我們應該進一步去分析問題,為什麼一個 Vector 會占據了系統 99% 的內存,誰阻止了垃圾回收機制對它的回收。

查看報告之二:分析問題的所在

首先我們簡單回顧下 JAVA 的內存回收機制,內存空間中垃圾回收的工作由垃 圾回收器 (Garbage Collector,GC) 完成的,它的核心思想是:對虛擬機可用內 存空間,即堆空間中的對象進行識別,如果對象正在被引用,那麼稱其為存活對 象,反之,如果對象不再被引用,則為垃圾對象,可以回收其占據的空間,用於 再分配。

在垃圾回收機制中有一組元素被稱為根元素集合,它們是一組被虛擬機直接引 用的對象,比如,正在運行的線程對象,系統調用棧裡面的對象以及被 system class loader 所加載的那些對象。堆空間中的每個對象都是由一個根元素為起點 被層層調用的。因此,一個對象還被某一個存活的根元素所引用,就會被認為是 存活對象,不能被回收,進行內存釋放。因此,我們可以通過分析一個對象到根 元素的引用路徑來分析為什麼該對象不能被順利回收。如果說一個對象已經不被 任何程序邏輯所需要但是還存在被根元素引用的情況,我們可以說這裡存在內存 洩露。

現在,讓我們開始真正的尋找內存洩露之旅,點擊“Details ”鏈接,可以看 到如圖 8 所示對可疑對象 1 的詳細分析報告。

圖 8. 可疑對象 1 的詳細分析報告

我們查看下從 GC 根元素到內存消耗聚集點的最短路徑:

圖 9. 從根元素到內存消耗聚集點的最短路徑

我們可以很清楚的看到整個引用鏈,內存聚集點是一個擁有大量對象的集合, 如果你對代碼比較熟悉的話,相信這些信息應該能給你提供一些找到內存洩露的 思路了。

接下來,我們再繼續看看,這個對象集合裡到底存放了什麼,為什麼會消耗掉 如此多的內存。

圖 10. 內存消耗聚集對象信息

在這張圖上,我們可以清楚的看到,這個對象集合中保存了大量 Person 對象 的引用,就是它導致的內存洩露。

至此,我們已經擁有了足夠的信息去尋找洩露點,回到代碼,我們發現,是下 面的代碼導致了內存洩露 :

清單 1. 內存洩漏的代碼段

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 的幫助文檔。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved