1. 程式人生 > >eclipse 使用MAT分析堆疊

eclipse 使用MAT分析堆疊

1. 介紹

Eclipse MAT是eclipse提供的外掛用於分析JAVA heap。試過很多分析heap的,但是沒有比這個更好用的了。

PS:在mac high sierra上直接下載獨立執行的MAT貌似會出問題卡死,我是本地直接下載了個。

請先閱讀下MAT官方的DOC:MAT官方DOC

2. 基本概念

2.1 堆中包含的內容

  • All Objects:Class, fields, primitive values and references
  • All Classes:Classloader, name, super class, static fields
  • Garbage Collection Roots:Objects defined to be reachable by the JVM
  • Thread Stacks and Local Variables:The call-stacks of threads at the moment of the snapshot, and per-frame information about local objects

2.2 Shallow VS Retined heap

Shallow heap size : 物件本身佔用的大小,不包含其引用的物件Retained heap: 物件本身大小加上其所有引用物件的真實大小

PS: 可見實際佔用看見或者回收的空間要看Retained heap

2.3 Dominator Tree

一個Object構成的樹(DAG),最頂端的節點的retained memory由其所有子節點構成,作用主要是方便找佔用retained heap size最大的物件

2.4 gc root

GC ROOT本質就是一個物件,這個物件包含了一系列必須保證活躍的引用(可以理解成一個DAG)。JVM的GC就是判斷哪些不能被回收,剩下的全部回收就行。即,遍歷所有物件做GC ROOT可達性分析,可達的則不回收,不可達的則進行GC。

用MAT文件裡面的話來解釋就是:A garbage collection root is an object that is accessible from outside the heap. The following reasons make an object a GC root

可作為gc root的物件,完整列表參考下MAT官方文件,我重點羅列幾個

  1. JNI相關的物件和引用
  2. 靜態變數
  3. 持有監視器鎖的物件
  4. native棧上的物件和引用

2.5 一些選項說明

  • biggest object by retained size:顯示在記憶體較大的物件資訊
  • list objects -- with outgoing references : 檢視這個物件持有的外部物件引用。
  • list objects -- with incoming references : 檢視這個物件被哪些外部物件引用。
  • show objects by class -- with outgoing references :檢視這個物件型別持有的外部物件引用
  • show objects by class -- with incoming references :檢視這個物件型別被哪些外部物件引用
  • paths to gc root : 顯示不同型別引用(上文中提到的Strong ,soft,weak )到跟節點的路徑。
  • merge shorest path to gc root : 合併最短路徑到root節點。
  • java basics:
    • classloader 該物件對應的classloader資訊 。
    • thread details :執行緒資訊
    • thread stacks :執行緒堆疊
    • find String : 在這個物件中查詢需要的字串
    • group by : 根據某個欄位統計出現的個數
  • leak Identification -- top consumers :幾個大消耗記憶體的物件

另外計算retsined size也是很常用的功能,MAT預設不顯示這一列,如果有需要的可以自己勾選算一下:

3. 實踐

3.1 classloader記憶體洩漏排查

參考文獻2和4講了classloader記憶體洩漏問題排查方法,可以學習下。我沒有記憶體洩漏的例子,但是實際過程中有碰到個perm oom的問題。

例如產生一個perm gen OOM,就猜測可能由classloader記憶體洩漏引起。因為perm區主要就存放一些class元資料、靜態變數。比如有時候載入了一些java agent,一些classloader載入了不少類,但是分配的perm gen太小,就導致perm gen OOM了。當然這個OOM也不一定是記憶體洩漏,可能是分配的perm區真的太小了,我就碰到了這樣的情況:

總共分配了32M的PERM,平時使用就達到了29M,因為開了個java agent多加了幾M就直接OOM了,因此也順便用MAT 分析了下heap

開啟classloader瀏覽器

看classloader的retained size,合起來差不都32M的樣子,有個叫ArthasClasssLoader的,就是我說的java agent,差不多佔用2M。。也是本次OOM的罪魁禍首。

PS: classLoader和一般的Obect不太一樣,右鍵勾選的時候會問你要看Class Loader本身的資訊還是其定義的Classses資訊。class Loader本身資訊如果檢視Immediate Dominators資訊的話只有個ROOT。這也很好理解,class Loader是rt.jar裡面的,是通過boorstrap classloader載入的,屬於system class,自然其gc不會依賴別的class,屬於最dominant的class了

3.2 某些類一直沒有被GC問題排查

有時候要看為什麼這個類沒有被GC,不符合預期,那麼只要看看他在哪些GC ROOT物件的引用鏈上。按照如下操作,這裡我排除了一些虛、弱軟引用,只關注強引用即可。因為其他程度弱的引用反正都會被GC的,不會是物件異常沒被回收的罪魁禍首。

最後按照羅列出來的引用鏈,下鑽去檢視,肯定最後會找到一個gc root object:

這裡可以看到這個Java Local型別的物件就是之前羅列的可以作為gc root object的

3.3 immediate object和gc root來查詢某個物件的root dominated not的區別

某個物件肯定會關聯一個immediate object,當這個immediate object的所有例項被GC後,那麼這個物件也肯定會被GC。通過如下方式查詢關聯的immediate object是最快。但是這種方式只能查詢和哪個immediate object關聯,不能檢視immediate object的引用資訊。

如果需要檢視immediate dominators的引用資訊,還要按照如下操作,該dominator object有哪個外部物件持有的引用,從而瞭解需要哪些物件

當然很容易聯想到用GC ROOT查詢也是可以的,只不過gc root查詢的話展現的內容層次更多些,本質上一樣的, 可以看到最後都是定位到ResuableIterator@)xe0a54ce0這個物件

3.4 檢視某個物件dominate 了哪些物件

3.3節我們是檢視某個物件被其他什麼物件和引用dominate。有時候需要檢視某個物件dominate 哪些子物件也很簡單,直接操作Open in Dominatoe Tree

3.5 執行緒相關

持有某個物件例項的執行緒,直接按照如下操作即可:

4. 總結

MAT功能強大,本身針對其主要用法配合一些應用場景做了一些介紹,更多可以自己再配合官方文件使用一番,加強理解。

參考資料

  1. 知乎提問R大的回答,理解gc root
  2. classloader記憶體洩露的總結
  3. Classloader leaks I – How to find classloader leaks with Eclipse Memory Analyser (MAT)
  4. Solve "PermGen space OutOfMem