MAT分析OOM問題

生產環境,我們的 Flink 作業偶爾會出現 heap OOM,那麼當出現這種情況我們會怎麼辦?通常來說會通過 jmap 命令去將作業的 heap dump 一份文件出來,可是 jmap 導出的文件我們也看不懂啊,那麼該怎麼分析呢?今天推薦 memory analyzer(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),檢查代碼是否存在對象生命週期太長、持有狀態時間過長的情況。

jmap 命令生成堆信息

jmap -dump:live,format=b,file=E:/jmap/heap.dump pid

這樣在E盤的jmap文件夾裏會有一個map.bin的堆信息文件

這樣在E盤的jmap文件夾裏會有一個map.bin的堆信息文件

將堆信息導入到mat中分析

生成分析報告

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正則搜索一下我們自己的類,排序後看看哪些相對是佔用比較大的。

左邊可以看到類的詳細使用,比如所屬包,父類是誰,所屬的類加載器,內存地址,佔用大小和回收情況等

這裏可以看到上面3個選項,分別生成overview、leak suspects、top components數據,但是這兒生成的不是圖表,如果要看圖表在(Overview)中的Action標籤裏點擊查看。

這個是Overview中的 Heap Dump Overview視圖,從工具欄中點開,這是一個全局的內存佔用信息

然後可以點開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這個工具還有很多的用法,這裏把我瞭解的分享給大家,不管如何,最終我們需要得出系統的內存佔用,然後對其進行代碼或架構,服務器的優化措施!

本文轉載自作者:學無止境 

原文鏈接:https://www.cnblogs.com/duanxz/p/6046055.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章