eclipse MAT (二)分析報告的生成和記憶體消耗分析三步曲
在文章eclipse MAT (二)進行OutOfMemoryError的診斷分析
生成了一個檔案java_pid3708.hprof,這個檔案 在你的專案的根目錄下
一,生成分析報告
首先,啟動前面安裝配置好的 Memory Analyzer tool , 然後選擇選單項 File- Open Heap Dump 來載入需要分析的堆轉儲檔案。檔案載入完成後,你可以看到如圖 1所示的介面:
圖 1. 概覽
通過上面的概覽,我們對記憶體佔用情況有了一個總體的瞭解。
從上圖可以看到它的大部分功能,在餅圖上,你會發現轉儲的大小和數量的類,物件和類載入器。
正確的下面,餅圖給出了一個印象最大的物件轉儲。移動你的滑鼠一片看到物件中的物件的細節檢查在左邊。下面的Action標籤中:
- Histogram可以列出記憶體中的物件,物件的個數以及大小。
-
Dominator Tree可以列出那個執行緒,以及執行緒下面的那些物件佔用的空間。
-
Top consumers通過圖形列出最大的object。
-
Leak Suspects通過MA自動分析洩漏的原因。
Histogram
- Class Name : 類名稱,java類名
-
Objects : 類的物件的數量,這個物件被建立了多少個
-
Shallow Heap :一個物件記憶體的消耗大小,不包含對其他物件的引用
-
Retained Heap :是shallow Heap的總和,也就是該物件被GC之後所能回收到記憶體的總和
一般來說,Shallow Heap堆中的物件是它的大小和保留記憶體大小相同的物件是堆記憶體的數量時,將釋放物件被垃圾收集。
保留設定一組主要的物件,例如一個特定類的所有物件,或所有物件的一個特定的類裝入器裝入的類或者只是一群任意物件,是釋放的組物件如果所有物件的主要設定變得難以接近的。保留設定包括這些物件以及所有其他物件只能通過這些物件。保留大小是總堆大小中包含的所有物件的保留。摘自eclipse
關於的詳細講解,建議大家檢視Shallow heap & Retained heap
這兒藉助工具提供的regex正則搜尋一下我們自己的類,排序後看看哪些相對是佔用比較大的。
左邊可以看到類的詳細使用,比如所屬包,父類是誰,所屬的類載入器,記憶體地址,佔用大小和回收情況等
這兒有個工具可以根據自己的需求分組查詢,預設根據class分組,類似我們sql裡的group by了~~
這裡可以看到上面3個選項,分別生成overview、leak suspects、top components資料,但是這兒生成的不是圖表,如果要看圖表在(Overview)中的Action標籤裡點選檢視。
這個是Overview中的 Heap Dump Overview檢視,從工具欄中點開,這是一個全域性的記憶體佔用資訊
Used heap dump | 79.7 MB |
Number of objects | 1,535,626 |
Number of classes | 8,459 |
Number of class loaders | 74 |
Number of GC roots | 2,722 |
Format | hprof |
JVM version | |
Time | 格林尼治標準時間+0800上午9時20分37秒 |
Date | 2014-7-2 |
Identifier size | 32-bit |
File path | E:\jmap\map.bin |
File length | 108,102,005 |
|
然後可以點開SystemProperties和Thread Overview進行檢視,我這裡就不貼了內容比較多。
Dominator Tree
我們可以看到ibatis佔了較多記憶體
Top consumers
這張圖展示的是佔用記憶體比較多的物件的分佈,下面是具體的一些類和佔用。
按等級分佈的類使用情況,其實也就是按使用次數檢視,java.lang.Class被排在第一
還有一張圖是我們比較關心的,那就是按包名看佔用,根據包我們知道哪些公共用的到jar或自己的包占用
這樣就可以看到包和包中哪些類的佔用比較高。
2,先檢查一下 MAT 生成的一系列檔案。
可以看到 MAT 工具提供了一個很貼心的功能,將報告的內容壓縮打包到一個 zip 檔案,並把它存放到原始堆轉儲檔案的存放目錄下,這樣如果您需要和同事一起分析這個記憶體問題的話,只需要把這個小小的 zip 包發給他就可以了,不需要把整個堆檔案發給他。並且整個報告是一個 HTML 格式的檔案,用瀏覽器就可以輕鬆開啟。
接下來我們就可以來看看生成的報告都包括什麼內容,能不能幫我們找到問題所在吧。您可以點選工具欄上的 Leak Suspects 選單項來生成記憶體洩露分析報告,也可以直接點選餅圖下方的 Reports->Leak Suspects 連結來生成報告。
二、分析三步曲
通常我們都會採用下面的“三步曲”來分析記憶體洩露問題:
首先,對問題發生時刻的系統記憶體狀態獲取一個整體印象。
第二步,找到最有可能導致記憶體洩露的元凶,通常也就是消耗記憶體最多的物件
接下來,進一步去檢視這個記憶體消耗大戶的具體情況,看看是否有什麼異常的行為。
下面將用一個基本的例子來展示如何採用“三步曲”來檢視生產的分析報告。
檢視報告之一:記憶體消耗的整體狀況
如圖 4 所示,在報告上最醒目的就是一張簡潔明瞭的餅圖,從圖上我們可以清晰地看到一個可疑物件消耗了系統 99% 的記憶體。
在圖的下方還有對這個可疑物件的進一步描述。我們可以看到記憶體是由 java.util.Vector 的例項消耗的,com.ibm.oti.vm.BootstrapClassLoader 負責這個物件的載入。這段描述非常短,但我相信您已經可以從中找到很多線索了,比如是哪個類佔用了絕大多數的記憶體,它屬於哪個元件等等。
接下來,我們應該進一步去分析問題,為什麼一個 Vector 會佔據了系統 99% 的記憶體,誰阻止了垃圾回收機制對它的回收。
檢視報告之二:分析問題的所在
首先我們簡單回顧下 JAVA 的記憶體回收機制,記憶體空間中垃圾回收的工作由垃圾回收器 (Garbage Collector,GC) 完成的,它的核心思想是:對虛擬機器可用記憶體空間,即堆空間中的物件進行識別,如果物件正在被引用,那麼稱其為存活物件,反之,如果物件不再被引用,則為垃圾物件,可以回收其佔據的空間,用於再分配。
在垃圾回收機制中有一組元素被稱為根元素集合,它們是一組被虛擬機器直接引用的物件,比如,正在執行的執行緒物件,系統呼叫棧裡面的物件以及被 system class loader 所載入的那些物件。堆空間中的每個物件都是由一個根元素為起點被層層呼叫的。因此,一個物件還被某一個存活的根元素所引用,就會被認為是存活物件,不能被回收,進行記憶體釋放。因此,我們可以通過分析一個物件到根元素的引用路徑來分析為什麼該物件不能被順利回收。如果說一個物件已經不被任何程式邏輯所需要但是還存在被根元素引用的情況,我們可以說這裡存在記憶體洩露。
現在,讓我們開始真正的尋找記憶體洩露之旅,點選“Details ”連結,可以看到如圖 5 所示對可疑物件 1 的詳細分析報告。
- 我們檢視下從 GC 根元素到記憶體消耗聚集點的最短路徑:
我們可以很清楚的看到整個引用鏈,記憶體聚集點是一個擁有大量物件的集合,如果你對程式碼比較熟悉的話,相信這些資訊應該能給你提供一些找到記憶體洩露的思路了。
點選滑鼠,在List Objects-> with outgoing references下可以檢視該類都引用了什麼物件,由此檢視是否因為其他物件導致的記憶體問題。
下面繼續檢視pool的gc ROOT
如下圖所示的上下文選單中選擇 Path To GC Roots -> exclude weak references, 過濾掉弱引用,因為在這裡弱引用不是引起問題的關鍵。
進入檢視即可,我這兒的程式碼沒有問題,就不用貼了。
接下來,我們再繼續看看,這個物件集合裡到底存放了什麼,為什麼會消耗掉如此多的記憶體。
在這張圖上,我們可以清楚的看到,這個物件集合中儲存了大量 Person 物件的引用,就是它導致的記憶體洩露。
另外推薦學習資料:
https://blog.csdn.net/alli0968/article/details/52460008?utm_source=blogxgwz2