天天看點

記憶體分析工具 MAT 的使用

1 記憶體洩漏的排查方法

Dalvik Debug Monitor Server (DDMS) 是 ADT插件的一部分,其中有兩項功能可用于記憶體檢查 :

·    heap 檢視堆的配置設定情況

·    allocation tracker跟蹤記憶體配置設定情況

DDMS 這兩項功能有助于找到記憶體洩漏的操作行為。

Eclipse Memory Analysis Tools (MAT) 是一個分析 Java堆資料的專業工具,用它可以定位記憶體洩漏的原因。

工具位址 : https://www.eclipse.org/mat/

1.1 觀察 Heap

·        運作程式,然後進入 DDMS管理界面,如下:

記憶體分析工具 MAT 的使用

PS : 點選工具欄上的  

記憶體分析工具 MAT 的使用

來更新統計資訊

點選右側的 Cause GC 按鈕或工具欄上的  

記憶體分析工具 MAT 的使用

即可檢視目前的堆情況,如下: 

記憶體分析工具 MAT 的使用

主要關注兩項資料:

o    Heap Size 堆的大小,當資源增加,目前堆的空餘空間不夠時,系統會增加堆的大小,若超過上限 (例如 64M,視平台和具體機型而定)則會被殺掉

o    Allocated 堆中已配置設定的大小,這是應用程式實際占用的記憶體大小,資源回收後,此項資料會變小

·        檢視操作前後的堆資料,看是否有記憶體洩漏 

對單一操作(比如添加頁,删除頁)進行反複操作,如果堆的大小一直增加,則有記憶體洩漏的隐患。

1.2 利用MAT分析記憶體堆

DDMS 可以将目前的記憶體 Dump成一個 hprof格式的檔案,MAT 讀取這個檔案後會給出友善閱讀的資訊,配合它的查找,對比功能,就可以定位記憶體洩漏的原因。

·        擷取 hprof檔案 

點選工具欄上的  

記憶體分析工具 MAT 的使用

按鈕,将記憶體資訊儲存成檔案。 如果是用 MAT Eclipse 插件擷取的 Dump檔案,則不需要經過轉換,Adt會自動進行轉換然後打開。

·        轉換 hprof檔案 

DDMS Dump 出的檔案要經過轉換才能被 MAT識别,Android SDK提供了這個工具 hprof-conv (位于 sdk/tools下)

·    ./hprof-conv xxx-a.hprof xxx-b.hprof

·        用 MAT打開轉換後的 hprof檔案 

記憶體分析工具 MAT 的使用

1.3  Histogram 查詢

用的最多的功能是 Histogram,點選 Actions下的 Histogram項将得到 Histogram結果:

記憶體分析工具 MAT 的使用

它按類名将所有的執行個體對象列出來,可以點選表頭進行排序,在表的第一行可以輸入正規表達式來比對結果 :

記憶體分析工具 MAT 的使用

在某一項上右鍵打開菜單選擇 list objects ->with incoming refs 将列出該類的執行個體:

記憶體分析工具 MAT 的使用

它展示了對象間的引用關系,比如展開後的第一個子項表示這個 HomePage(0x420ca5b0)被 HomePageContainer(0x420c9e40)中的 mHomePage屬性所引用.

快速找出某個執行個體沒被釋放的原因,可以右健 Path to GC Roots-->exclue all phantom/weak/soft etc. reference :

記憶體分析工具 MAT 的使用

得到的結果是:

記憶體分析工具 MAT 的使用

從表中可以看出 PreferenceManager -> … ->HomePage這條線路就引用着這個 HomePage執行個體。用這個方法可以快速找到某個對象的 GC Root,一個存在 GC Root的對象是不會被 GC回收掉的.

1.4  Histogram 對比

為查找記憶體洩漏,通常需要兩個 Dump結果作對比,打開 Navigator History面闆,将兩個表的 Histogram結果都添加到 Compare Basket中去 :

記憶體分析工具 MAT 的使用

添加好後,打開 Compare Basket面闆,得到結果:

記憶體分析工具 MAT 的使用

點選右上角的 ! 按鈕,将得到比對結果:

記憶體分析工具 MAT 的使用

注意,上面這個對比結果不利于查找差異,可以調整對比選項:

記憶體分析工具 MAT 的使用

再把對比的結果排序,就可得到直覺的對比結果:

記憶體分析工具 MAT 的使用

也可以對比兩個對象集合,方法與此類似,都是将兩個 Dump結果中的對象集合添加到Compare Basket中去對比。找出差異後用 Histogram查詢的方法找出 GC Root,定位到具體的某個對象上。

1.5  例子

舉例一個典型的分析記憶體洩漏的過程:

1.  使用 Heap檢視目前堆大小為 23.00M

2.  添加一個頁後堆大小變為 23.40M

3.  将添加的一個頁删除,堆大小為 23.40M

4.  多次操作,結果仍相似,說明添加/删除頁存在記憶體洩漏 (也應注意排除其它因素的影響)

5.  Dump 出操作前後的 hprof 檔案 (1.hprof,2.hprof),用 mat打開,并得到 histgram結果

6.  使用 HomePage字段過濾 histgram結果,并列出該類的對象執行個體清單,看到兩個表中的對象集合大小不同,操作後比操作前多出一個 HomePage,說明确實存在洩漏

7.  将兩個清單進行對比,找出多出的一個對象,用查找 GC Root的方法找出是誰串起了這條引用線路,定位結束

PS :

·        很多時候堆增大是 Bitmap引起的,Bitmap在 Histogram中的類型是 byte [],對比兩個 Histogram中的 byte[] 對象就可以找出哪些 Bitmap有差異

·        多使用排序功能,對找出差異很有用

2 記憶體洩漏的原因分析

總結出來隻有一條: 存在無效的引用! 

良好的子產品設計以及合理使用設計模式有助于解決此問題。

3 Tips

·    使用 android:largeHeap="true"标記 (API Level >= 11) 

在 AndroidManifest.xml中的 Application節點中聲明即可配置設定到更大的堆記憶體, android:largeHeap标記在 Android系統應用中也有廣泛的應用 ,比如 Launcher, Browser這些記憶體大戶上均有使用.

4 參考

·    DDMS 官方教程 http://developer.android.com/tools/debugging/ddms.html

·    MAT 下載下傳 http://www.eclipse.org/mat/downloads.php

·    MAT 使用 http://android-developers.blogspot.tw/2011/03/memory-analysis-for-android.html

 同僚起草,整理分享,可以轉載收錄。