首先介紹一下MAT的安裝
下載地址:https://eclipse.org/mat/downloads.php
選擇自己系統相應的版本下載,下載完得到一個zip文件,解壓后雙擊EXE文件就可以直接使用了
使用jmap得到的.hprof 文件,使用MAT工具打開進行進一步的分析,選擇第一個Leak Suspects Report
Histogram 可以列出內存中的對象,對象的個數以及大小,需要重點關注
它按類名將所有的實例對象列出來,點擊表頭(Class Name)可以排序,第一行輸入正則表達式可以過濾篩選 ;
Shallow Heap :一個對象內存的消耗大小,不包含對其他對象的引用;
Retained Heap :是shallow Heap的總和,也就是該對象被GC之后所能回收的內存大小;
在某一項上右鍵打開菜單選擇 list objects :
with incoming references 將列出哪些類引入該類;
with outgoing references 列出該類引用了哪些類
Dominator Tree可以列出那個線程,以及線程下面的那些對象占用的空間
可以列出內存中存活的大對象列表,優點是有Percentage字段,可以看各種情況的百分比。
分組工具可以根據自己的需求分組查找,默認根據class分組,本文中是根據 package分組,建議按package進行分組,可以清楚的跟進自己寫的包的情況
快速找出某個實例沒被釋放的原因,可以右健 Path to GC Roots-->exclude all phantom/weak/soft etc. references
它展示了對象間的引用關系,比如SSLSocketImpl @0xa124b208被PushNotificationManager 實例中的socket屬性所引用。
Top consumers通過圖形列出最大的object
多種維度(包括 類大小、類加載器、包名)展示占用內存比較多的對象的分布,從而定位內存資源主要耗費在哪些地方!
Leak Suspects通過MA自動分析泄漏的原因,需要重點關注
Java 的內存泄漏問題比較難以定位,下面針對一些常見的內存泄漏場景做介紹:
- 持續在堆上創建對象而不釋放。例如,持續不斷的往一個列表中添加對象,而不對列表清空。這種問題,通常可以給程序運行時添加 JVM 參數
-Xmx
指定一個較小的運行堆大小,這樣可以比較容易的發現這類問題。 - 不正確的使用靜態對象。因為 static 關鍵字修飾的對象的生命周期與 Java 程序的運行周期是一致的,所以垃圾回收機制無法回收靜態變量引用的對象。所以,發生內存泄漏問題時,我們要着重分析所有的靜態變量。
- 對大 String 對象調用 String.intern()方法,該方法會從字符串常量池中查詢當前字符串是否存在,若不存在就會將當前字符串放入常量池中。而在 jdk6 之前,字符串常量存儲在
PermGen
區的,但是默認情況下PermGen
區比較小,所以較大的字符串調用此方法,很容易會觸發內存溢出問題。 - 打開的輸入流、連接沒有爭取關閉。由於這些資源需要對應的內存維護狀態,因此不關閉會導致這些內存無法釋放。