Java程式記憶體分析:使用mat工具分析記憶體佔用
MAT 不是一個萬能工具,它並不能處理所有型別的堆儲存檔案。但是比較主流的廠家和格式,例如 Sun, HP, SAP 所採用的 HPROF 二進位制堆儲存檔案,以及 IBM 的 PHD 堆儲存檔案等都能被很好的解析。下面來看看要怎麼做呢,也許對你有用。官方文件:http://help.eclipse.org/luna/index.jsp?topic=/org.eclipse.mat.ui.help/welcome.html
造成OutOfMemoryError原因一般有2種:
1、記憶體洩露,物件已經死了,無法通過垃圾收集器進行自動回收,通過找出洩露的程式碼位置和原因,才好確定解決方案;
2、記憶體溢位,記憶體中的物件都還必須存活著,這說明Java堆分配空間不足,檢查堆設定大小(-Xmx與-Xms),檢查程式碼是否存在物件生命週期太長、持有狀態時間過長的情況。
1. 用jmap生成堆資訊
這樣在E盤的jmap資料夾裡會有一個map.bin的堆資訊檔案
2. 將堆資訊匯入到mat中分析
3. 生成分析報告
mat可以為我們生成多個報告:
下面來看看生成的這些資料對我們有什麼幫助
從上圖可以看到它的大部分功能,在餅圖上,你會發現轉儲的大小和數量的類,物件和類載入器。
正確的下面,餅圖給出了一個印象最大的物件轉儲。移動你的滑鼠一片看到物件中的物件的細節檢查在左邊。下面的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或自己的包占用
這樣就可以看到包和包中哪些類的佔用比較高。
Leak Suspects
從這份報告,看到該圖深色區域被懷疑有記憶體洩漏,可以發現整個heap只有79.7M記憶體,深色區域就佔了62%。所以,MAT通過簡單的報告就說明了專案是有可疑程式碼的,具體點開詳情來找到類,
點選滑鼠,在List Objects-> with outgoing references下可以檢視該類都引用了什麼物件,由此檢視是否因為其他物件導致的記憶體問題。
下面繼續檢視pool的gc ROOT
如下圖所示的上下文選單中選擇 Path To GC Roots -> exclude weak references, 過濾掉弱引用,因為在這裡弱引用不是引起問題的關鍵。
進入檢視即可,我這兒的程式碼沒有問題,就不用貼了。
The classloader/component "org.apache.catalina.loader.WebappClassLoader @ 0xa34cde8" occupies 19,052,864 (22.80%) bytes. The memory is accumulated in one instance of "java.util.HashMap$Entry[]" loaded by "<system class loader>".
Keywords
java.util.HashMap$Entry[]
org.apache.catalina.loader.WebappClassLoader @ 0xa34cde8
這段話是在工具中提示的,他告訴我們WebappClassLoader佔了19,052,864 位元組的容量,這是tomcat的類載入器,JDK自帶的系統類載入器中佔用比較多的是HashMap。這個其實比較正常,大家經常用map作為儲存容器。
除了在上一頁看到的描述外,還有Shortest Paths To the Accumulation Point和Accumulated Objects部分,這裡說明了從GC root到聚集點的最短路徑,以及完整的reference chain。觀察Accumulated Objects部分,java.util.HashMap的retained heap(size)最大,所以明顯類例項都聚集在HashMap中了。
來看看Accumulated Objects by Class區域,這裡能找到被聚集的物件例項的類名。java.util.HashMap類上頭條了,被例項化了5573次,從這兒看出這個程式不存在什麼問題,因為這個數字是比較正常的,但是當出問題的時候我們都會看到比較大的自定義類會在前面,而且佔用是相當高。
當然,mat這個工具還有很多的用法,這裡把我瞭解的分享給大家,不管如何,最終我們需要得出系統的記憶體佔用,然後對其進行程式碼或架構,伺服器的優化措施!
參考文獻: