eclipse 使用MAT分析堆棧

1. 介紹

Eclipse MAT是eclipse提供的插件用於分析JAVA heap。試過不少分析heap的,可是沒有比這個更好用的了。html

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

請先閱讀下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: 對象自己大小加上其全部引用對象的真實大小dom

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

2.3 Dominator Tree

一個Object構成的樹(DAG),最頂端的節點的retained memory由其全部子節點構成,做用主要是方便找佔用retained heap size最大的對象jsp

2.4 gc root

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

用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官方文檔,我重點羅列幾個ui

  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默認不顯示這一列,若是有須要的能夠本身勾選算一下:spa

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 OutOfMemoryError"
相關文章
相關標籤/搜索