Mat使用詳解

zhao發表於2020-11-28

背景

筆記中躺了很久的文章,今天用到Mat時發現之前寫的內容還算清晰,分享出來;
如下所舉例使用的dump檔案是針對之前使用的ignite庫溢位時的dump檔案;關於ignite的概念此處不再敘述,本篇文章重點則在於Mat即可

Mat的作用

MAT是Memory Analyzer tool的縮寫,是一種快速,功能豐富的Java堆分析工具,能幫助你查詢記憶體洩漏和減少記憶體消耗。很多情況下,我們需要處理測試提供的hprof檔案,分析記憶體相關問題,那麼MAT也絕對是不二之選。 Eclipse可以下載外掛結合使用,也可以作為一個獨立分析工具使用;下載地址:https://pan.baidu.com/s/1NDUR0E3WGrktm1qwoZHWfg
提取碼:agxr ;不用謝,雷鋒

Mat的使用步驟

開啟Mat後File>OpenHeapDump開啟一個對應的dump檔案後,此時對應的開啟後結果如圖所示:

預設情況下開啟該dump檔案後,直接展示的就是一個Overview(概覽)的頁籤,其中可以看到上面標註為(1,2)的地方所對應的圖示與Overview頁籤中所對應的部分圖示是相似的;如果你不小心關掉了Overview的頁籤,那麼直接單擊當前dump頁籤第一行導航欄的第一個 I字的圖示即可,同理,如果此時想要開啟Histogram,那麼在不開啟Overview的情況下,直接點選第一行導航欄的第二個圖示即可;......

Overview下功能解釋

Overview頁簽下分別包含了:Actions,Reports,Step By Step 三大塊功能;每一塊功能下的子集所對應的作用分別是:

  • Actions:

    • Histogram 列出每個類所對應的物件個數,以及所佔用的記憶體大小;

    • Dominator Tree 以佔用總記憶體的百分比的方式來列舉出所有的例項物件,注意這個地方是直接列舉出的對應的物件而不是類,這個檢視是用來發現大記憶體物件的

    • Top Consumers:按照類和包分組的方式展示出佔用記憶體最大的一個物件

    • Duplicate Classes:檢測由多個類載入器所載入的類資訊(用來查詢重複的類)

  • Reports:

    • Leak Suspects:通過MAT自動分析當前記憶體洩露的主要原因

    • Top Components:Top元件,列出大於總堆1%的元件的報告

  • Step By Step:

    • Component Report:元件報告,分析屬於公共根包或類載入器的物件;

    上述所有被標註加粗的部分,是記憶體溢位dump分析時較為常用的功能點也是下面主要講解的內容。

原創宣告:作者:Arnold.zhao 部落格園地址:https://www.cnblogs.com/zh94

Histogram

通過Histogram 列出每個類所對應的物件個數,以及所佔用的記憶體大小;

此處選中一個ClassName單擊後,通過左上角Inspector可以看到當前類的回收情況,記憶體地址,等

補充解釋:

  • 欄位一:表示當前類所對應的物件數量

  • 欄位二:Shallow Size是物件本身佔據的記憶體的大小,不包含其引用的物件。對於常規物件(非陣列)的Shallow Size由其成員變數的數量和型別來定,而陣列的ShallowSize由陣列型別和陣列長度來決定,它為陣列元素大小的總和;

  • 欄位三:Retained Size=當前物件大小+當前物件可直接或間接引用到的物件的大小總和。(間接引用的含義:A->B->C,C就是間接引用) ,並且排除被GC Roots直接或者間接引用的物件;

關於紅框內的Statics,Attributes,Classhierarchy,Value則分別表示當前類的靜態變數,屬性,當前類的層次結構圖,以及當前類所對應的值Value;

注意:當前Histogram的列屬性:ClassName,Objects,ShallowHeap,RetainedHeap這幾個列屬性下面都是有提供一個輸入框,通過該輸入框可以進行相關類的檢索,比如:在ClassName下輸入一個正則.quark.那麼則獲取到所有包路徑為quark的類資訊;

Dominator Tree

以佔用總記憶體的百分比的方式來列舉出所有的例項物件,可以用來發現大記憶體物件;

如上圖所示:可以看到ConcurrentHashMap@0x60191cfa8這個物件佔據了98.92%的堆大小,所以基本就可以斷定,當前專案之所以會down機的主要原因是,ConcurrentHashMap溢位所導致的問題;

那麼當我們需要檢視,當前該ConcurrentHashMap@0x60191cfa8物件都引用了那些資料,以及當前該物件是被那幾個物件所引用的,如何檢視?

滑鼠在當前所要檢視的物件右鍵,點選List Objects可以看到分別提供了:with outgoing references(檢視當前該物件的所有的引用資訊) 和 with incoming references(檢視當前該物件是被那幾個物件所引用的) ;

原創宣告:作者:Arnold.zhao 部落格園地址:https://www.cnblogs.com/zh94

Leak Suspects

通過MAT自動分析當前記憶體洩露的主要原因

可以看到,當前MAT所給出記憶體洩露的主要原因是:當前例項java.util.concurrent.ConcurrentHashMap被載入自system class loader,共佔用了 98.92%的堆記憶體,這個例項被引用自org.apache.ignite.internal.processors.cache.binary.CacheObjectBinaryProcessorImpl並且這個CacheObjectBinaryProcessorImpl這個物件是載入自LaunchedURLClassLoader這個類載入器;

並且還給出了所對應的主要關鍵詞是:

java.util.concurrent.ConcurrentHashMap$Node[]
java.util.concurrent.ConcurrentHashMap
org.springframework.boot.loader.LaunchedURLClassLoader @ 0x6000a6860

基本上可以說是很詳細了,一語中的,如果想要檢視明細,可以直接點選detail,裡面有更詳細的說明,如下圖所示:

上圖分別說明了到該記憶體洩漏的物件的最快路徑,也就是列出了當前ConcurrentHashMapConcurrentHashMap@0x60191cfa8這個物件所對應的被引用關係:可以看到當前引起記憶體洩漏的ConcurrentHashMap被CacheObjectBinaryProcessorImpl@0x60191cea8這個物件的metadataLocCache這個屬性所引用,而CacheObjectBinaryProcessorImpl這個物件又被GridKernalContextImpl @ 0x601821bf8這個物件的cacheObjeProc這個屬性所引用,以此遞推;

除此之外,還有以下三個被隱藏的資訊,點選即可檢視明細:
Accumulated Objects in Dominator Tree (主控樹中的累積物件),Accumulated Objects by Class in Dominator Tree(主控樹中的按類累積物件 ,All Accumulated Objects by Class (按類列出所有的累積物件)

原創宣告:作者:Arnold.zhao 部落格園地址:https://www.cnblogs.com/zh94

Overview功能說明結尾

通過上述的解釋應該對當前Overview下的功能使用已經有了一個大概的瞭解,需要注意的是,Histogram 以及Dominator Tree時所主要提及的Shallow Size以及Retained Size以及在所列出的物件上右鍵檢視引用關係,GCROOTS,以及左上角所展示的屬性明細等功能 是適用於所有的功能模組的,後續不再贅述;

一級導航欄功能說明

檢視完上述關於Overview中的功能說明後,此處再來看一下Overview中不包含的一些功能

Thread_Overview

如下圖所示,點選一級導航欄的第5個圖示,可以用來檢視當前程式dump時的所有執行緒的堆疊資訊,通過分析下面所對應的堆疊資訊,可以很快速的定位到對應的執行緒所執行的方法等層級關係,以此來定位對應的異常問題;

OQL

用於查詢Java堆的類SQL查詢語言

Heap Dump Overview

點選一級導航欄的第6個圖示的下拉框下的 Heap Dump Overview,可以檢視全域性的記憶體佔用資訊

Find Object by address

檢視指定記憶體地址所對應的物件資訊;

常見溢位的幾個場景

1、執行緒所引用物件溢位
2、靜態屬性物件溢位

執行緒棧所引用物件溢位的場景,如下:

Mat各功能內還有很多小的子功能,使用過程中可逐步嘗試,此處不再贅述

原創宣告:作者:Arnold.zhao 部落格園地址:https://www.cnblogs.com/zh94