天天看點

Jmap+MAT 排查記憶體洩漏

最近在項目中自測的時候(壓力測試)遇到記憶體洩漏的情況,想檢視具體是哪個子產品甚至哪個類引起的問題,經同僚推薦使用Jmap+MAT的組合進行了一次嘗試,下面記錄一下,以便今後深入學習使用。

在程式出現記憶體溢出情況之前,想要觀察記憶體使用情況的話,可以借助atop指令檢視記憶體的使用情況。

這裡可以用一個linux下的指令(jps:虛拟機程序狀況工具)檢視所有Java相關線程的pid等資訊。

然後使用jmap(Java記憶體映像工具)指令,jmap是一個可以輸出記憶體中所有對象的工具,甚至可以将VM中的heap,以二進制輸出成文本。jmap-dump:format=b,file=heap.bin 8120可以将8120程序的記憶體heap輸出到heap.bin檔案裡。它可以列印出某個Java程序(使用pid)記憶體中所有“對象”的情況(如:産生哪些對象,及其數量)。

再借助MAT(将heap.bin導入到MAT中)生成記憶體消耗的詳細資訊。

MAT安裝與介紹

下載下傳位址:http://www.eclipse.org/mat/downloads.php。

通過MAT打開dump出來的記憶體檔案,打開後如下圖:

Jmap+MAT 排查記憶體洩漏

從上圖可以看到它的大部分功能。

1. Histogram可以列出記憶體中的對象,對象的個數以及大小。

2. Dominator Tree可以列出那個線程,以及線程下面的那些對象占用的空間。

3.Top consumers通過圖形列出最大的object。

4.Leak Suspects通過MA自動分析洩漏的原因。 Histogram如下圖: Objects:類的對象的數量。 Shallow size:就是對象本身占用記憶體的大小,不包含對其他對象的引用,也就是對象頭加成員變量(不是成員變量的值)的總和。 Retained size:是該對象自己的shallow size,加上從該對象能直接或間接通路到對象的shallow size之和。換句話說,retained size是該對象被GC之後所能回收到記憶體的總和。 我們發現ThreadLocal和bingo.persister.dao.Daos類的對象占用了很多空間。

Jmap+MAT 排查記憶體洩漏

Dominator Tree如下圖: 我們發現quartz的定時器的工作線程(10個)占了很多的記憶體空間

Jmap+MAT 排查記憶體洩漏

Top consumers如下圖: 這裡顯示了記憶體中最大的對象有哪些,他們對應的類是哪些,類加載器classloader是哪些。 有些時候,我們在這裡就可以看到代碼洩露的位置。

Jmap+MAT 排查記憶體洩漏

Leak Suspects如下圖: 從那個餅圖,該圖深色區域被懷疑有記憶體洩漏,可以發現整個heap才250M記憶體,深色區域就占了34%。後面的描述,告訴我們quartz線程占用了大量記憶體,并指出system class loader加載的"java.lang.ThreadLocal"執行個體的記憶體中聚集(消耗空間),并建議用關鍵字"java.lang.ThreadLocal$ThreadLocalMap$Entry[]"進行檢查。是以,MAT通過簡單的報告就說明了問題所在。

Jmap+MAT 排查記憶體洩漏

通過Leak Suspects的 Problem Suspect 1點選【 Details »】, 如下圖如下圖所示的上下文菜單中選擇 List objects -> with outgoning references, 檢視ThreadLocal都應用了些什麼對象。

Jmap+MAT 排查記憶體洩漏

現在看到ThreadLocal中引用的對象如下圖: 是dao對象 ps:該dao對象包含一個輕量級的ORM關系内容,是以Retained size比較大。

Jmap+MAT 排查記憶體洩漏

下面繼續檢視dao的gc ROOT 如下圖所示的上下文菜單中選擇 Path To GC Roots -> exclude weak references, 過濾掉弱引用,因為在這裡弱引用不是引起問題的關鍵。

Jmap+MAT 排查記憶體洩漏

從下圖中,可以看到在org.quartz.simpl.SimpleThreadPool中儲存了daos的引用。是以可以得出是是因為定時器在運作的過程中持有大量的Daos對象應起了記憶體洩露。為什麼會有那麼多的Daos呢,Daos不是一個無狀态的單例的、可以重用的嗎?繼續檢視spring配置檔案發現Daos的bean配置成scope="prototype",導緻定時任務又是每次調用都生産新的Daos執行個體。由于是Daos是無狀态的,修改為單例的,問題解決。

Jmap+MAT 排查記憶體洩漏

以上是通過MAT分析Tomcat應用程式,找到記憶體洩露的原因,并解決。

繼續閱讀