一拭荤、簡介
MAT是Memory Analyzer tool的縮寫,是一種快速纠俭,功能豐富的Java堆分析工具沿量,能幫助你查找內(nèi)存泄漏和減少內(nèi)存消耗。很多情況下冤荆,我們需要處理測試提供的hprof文件朴则,分析內(nèi)存相關(guān)問題,那么MAT也絕對是不二之選钓简。 Eclipse可以下載插件結(jié)合使用乌妒,也可以作為一個(gè)獨(dú)立分析工具使用,下載地址:MAT
二外邓、獲取hprof文件
我們先了解如何獲取hprof文件
在AS monitor 的 memory部分撤蚊,進(jìn)行如下操作:
左邊欄選擇Captures,在Heap Snapshot文件夾內(nèi)會(huì)生成對應(yīng)的hprof文件损话,再轉(zhuǎn)化為可供MAT使用的標(biāo)準(zhǔn)hprof文件侦啸,操作如下:
如果不用MAT槽唾,那么不需要轉(zhuǎn)為標(biāo)準(zhǔn)hprof文件,在右邊部門就能看到分析報(bào)表光涂,可以進(jìn)行對應(yīng)分析庞萍。但是建議還是使用MAT工具分析,功能更加全面些忘闻。
三钝计、MAT工具使用介紹
如何下載和安裝這里就不講了,自行百度或者google齐佳。
用工具打開標(biāo)準(zhǔn).hprof文件后界面如下:
我們主要分析Actions, 它包含了4個(gè)部分:
視圖 | 含義 |
---|---|
histogram | 列舉內(nèi)存中對象存在的個(gè)數(shù)和大小 |
Dominator tree | 該視圖會(huì)以占用總內(nèi)存的百分比來列舉所有實(shí)例對象私恬,注意這個(gè)地方是對象而不是類了,這個(gè)視圖是用來發(fā)現(xiàn)大內(nèi)存對象的 |
Top Consumers | 該視圖會(huì)顯示可能的內(nèi)存泄漏點(diǎn) |
Duplicate Classes | 該視圖顯示重復(fù)的類等信息 |
點(diǎn)擊他們能得到不同的視圖炼吴,下面來一一介紹:
3.1 Histogram:
點(diǎn)擊Histogram之后本鸣,會(huì)出現(xiàn)如下界面:
這個(gè)視圖中提供了多種方式來對對象進(jìn)行分類,這里為了分析方便硅蹦,我們選擇按包名進(jìn)行分類永高。
下面再來解釋下列名:
列名 | 含義 |
---|---|
Object | 該類在內(nèi)存當(dāng)中的對象個(gè)數(shù) |
Shallow Heap | 對象自身所占用的內(nèi)存大小,不包括它所引用的對象的內(nèi)存大小 |
Retained Heap | 該對象被垃圾回收器回收之后提针,會(huì)釋放的內(nèi)存大小 |
我們再來看一下右鍵菜單選項(xiàng):
1)List objects:
with outgoing references: 查看它所引用的對象
with incoming references: 查看它被哪些對象引用
2)Show objects by class
和List objects選項(xiàng)類似命爬,只不過列出的是類名。
3)Merge Shortest Paths to GC Roots
我們可以選擇排除一些類型的引用:
3.2 Dominator Tree:
通過“引用樹”的方式來展現(xiàn)內(nèi)存的使用情況的辐脖,通俗點(diǎn)來說饲宛,它是站在對象的角度來觀察內(nèi)存的使用情況的,主要看是否存在異常的大內(nèi)存對象
3.3 Top consumers 和 Duplicate Classes: 不常用嗜价,讀者可以自行使用下
四艇抠、簡單案例分析
案例:將Activity的實(shí)例被一個(gè)單例對象所持有,在旋轉(zhuǎn)屏幕的時(shí)候造成內(nèi)存泄漏
public class CommonUtils {
private static CommonUtils instance;
private Context context;
private CommonUtils(Context context){
this.context = context;
}
public static CommonUtils getInstance(Context context){
if(instance == null){
instance = new CommonUtils(context);
}
return instance;
}
}
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
CommonUtils.getInstance(this);//單例模式內(nèi)存泄漏
}
}
4.1生成hprof文件并導(dǎo)入MAT:
生成過程不贅述了,2份hprof文件 一份是沒有旋轉(zhuǎn)過屏幕的久锥, 一份是旋轉(zhuǎn)過屏幕多次的家淤,用來做泄漏和無泄漏的對比,幫助定位問題瑟由。
打開MAT 導(dǎo)入我們的2個(gè)hprof文件 Open File-->選擇文件-->Leak Suspects Report-->Finish
4.2生成比較結(jié)果表
兩個(gè)文件都分別先點(diǎn)擊Action中histogram視圖絮重,然后打開下面的面板Navigation History ,會(huì)發(fā)現(xiàn)有兩個(gè)histogram歹苦,分別選中histogram右鍵add to Compare Basket 添加到比較容器中青伤。
添加到比較容器,然后進(jìn)行比較:
比較之后生成Compared Tables:
然后通過合理的懷疑和猜測殴瘦,且通過對比狠角,找出有問題的類。當(dāng)然蚪腋,這個(gè)列子很簡單丰歌,而且位置也很清楚姨蟋,但是較為復(fù)雜的項(xiàng)目,這一步就是體力活了立帖。只能耐著性子一點(diǎn)點(diǎn)分析比較芬探。
定位到hasMemLeak.hprof存在內(nèi)存泄漏:
下一步,找到hasMemLeak.hprof對應(yīng)的histogram, 再去觀察MainActivtiy具體被哪些對象引用:
看到MainActivty被引用的地方這么多 而且一屏還顯示不完 我們又如何去判斷是哪個(gè)導(dǎo)致內(nèi)存泄漏的呢 MAT還有一個(gè)功能 就是通過遍歷GC Root樹去將那些有可能被GC回收的實(shí)例 將他們?nèi)コ▊渥ⅲ涸贕C Root樹中能找到的對象絕對不存在有內(nèi)存泄漏的實(shí)例 因?yàn)樗麄冊谶\(yùn)行時(shí)會(huì)被回收的嘛 只有找不到的那些才是:
排除虛引用厘惦、弱引用、軟引用哩簿,之后剩余的才是有分析價(jià)值的:
找到問題然后去修改代碼:
CommUtil instance = CommUtil.getInstance(getApplicationContext());
之后再抓hprof測試修改
分析總結(jié):
通過操作宵蕉,觀察android monitor的內(nèi)存變化,在橫豎屏切換或者頁面進(jìn)入退出之后节榜,內(nèi)存在短時(shí)間沒有明顯回落的羡玛,都是內(nèi)存泄漏的懷疑點(diǎn)。確認(rèn)幾個(gè)合理的懷疑范圍之后宗苍,通過抓取對比的hprof文件稼稿,先定位到泄漏的類,然后再通過分析它引用了誰或者誰引用了它來定位最終問題讳窟。同時(shí)可以通過排除虛引用让歼、弱引用、軟引用等等GC可以回收的引用來縮小分析范圍丽啡。
不得不承認(rèn)谋右,MAT分析內(nèi)存問題,還是比較麻煩的补箍,如果想圖方便的話改执,下期會(huì)講一個(gè)傻瓜式工具:LeakCanary.