在Dalvik運行時裡邊,程式員不能顯式地分配和釋放記憶體,所以這裡的記憶體泄露跟c和c++裡面的不同。在你的代碼裡邊,記憶體泄露就是你保留了一個並不再需要的類對象的引用。有時候僅僅一個引用就會阻礙gc對一大堆對象的回收。
必要的工具:
Android SDK提供了2個主要的剖析應用程式記憶體使用量情況的工具:DDMS裡的一個分頁Allocation Tracker和heap dumps。
Allocation Tracker是很有用的,特別是當你想得到程式在一定的時間裡記憶體的分配情況的一種感性認識的時候。但是它不能給你任何關於程式heap總體情況的任何 資訊。關於Allocation Tracker的更多資訊,請看文章Tracking Memory
Allocations 。
文章剩下的內容將把重點放在heap dumps,它是更強大的記憶體分析工具。
一個heap dump就是一個程式heap的快照,它儲存為一種叫做HPROF的二進位格式。Dalvik用的也是類似的格式,但是不完全一樣。這裡是Java的HPROF工具 。有很多方法去產生一個運行時應用程式的heap dump。其中一種就是使用在DDMS裡邊的Dump
HPROF file按鈕。如果想產生更精確的dump資料,可以在程式中使用android.os.Debug.dumpHprofData() 方法。
分析heap dump,你可以使用一些標準的工具比如jhat 或者Eclipse
Memory Analyzer(MAT) 。不過,首先你需要把.hprof檔案從Dalvik格式轉換成J2SE HPROF格式。你可以使用Android SDK提供的hprof-conv工具。例如:
hprof-conv dump.hprof converted-dump.hprof
在DDMS裡檢查heap的使用方式
Dalvik Debug Monitor Server(DDMS)是主要的Android調試工具之一,也是ADT Eclipse plug-in 的一部分,獨立的程式版本也可以在Android SDK的根目錄下的tools/下面找到。關於DDMS更多的資訊,請參考使用DDMS 。
我們來使用DDMS檢查這個應用的heap使用方式。你可以使用下面的兩種方法啟動DDMS:
- from Eclipse: click Window > Open Perspective > Other... > DDMS
- or from the command line: run
ddms
(or ./ddms
on Mac/Linux) in
the tools/
directory
選中進程,然後在 工具條上邊點擊 heap updates按鈕。這個時候切換到DDMS的VM Heap分頁。它會顯示每次gc後heap記憶體的一些基本資料。要看第一次gc後的資料內容,點擊Cause GC按鈕:
產生heap dump
我們現在使用heap dump來追蹤這個問題。點擊DDMS工具條上面的Dump HPROF檔案按鈕,選擇檔案儲存體位置,然後在運行hprof-conv。在這個例子裡我們使用獨立的MAT版本(版本1.0.1),從MAT網站下載 。
如果你使用ADT(它包含DDMS的外掛程式)同時也在eclipse裡面安裝了MAT,點擊“dump HPROF”按鈕將會自動地做轉換(用hprof-conv)同時會在eclipse裡面開啟轉換後的hprof檔案(它其實用MAT開啟)。
用MAT分析heap dumps
啟動MAT然後載入剛才我們產生的HPROF檔案。MAT是一個強大的工具,講述它所有的特性超出了本文的範圍,所以我只想示範一種你可以用來檢測 泄露的方法:長條圖(Histogram)視圖。它顯示了一個可以排序的類執行個體的列表,內容包括:shallow heap(所有執行個體的記憶體使用量總和),或者retained heap(所有類執行個體被分配的記憶體總和,裡面也包括他們所有引用的對象)。
MAT不會明確告訴我們這就是泄露,因為它也不知道這個東西是不是程式還需要的。
使用MAT比較heap dumps
調試記憶體泄露時,有時候適時比較2個地方的heap狀態是很有用的。這時你就需要產生2個單獨的HPROF檔案(不要忘了轉換格式)。下面是一些關於如何在MAT裡比較2個heap dumps的內容(有一點複雜):
- 第一個HPROF 檔案(using File > Open Heap Dump ).
- 開啟 Histogram view.
- 在Navigation History view裡 (如果看不到就從Window > Navigation History找 ), 右擊histogram 然後選擇Add to Compare Basket .
- 開啟第二個HPROF 檔案然後重做步驟2和3.
- 切換到Compare Basket view, 然後點擊Compare the Results (視圖右上方的紅色"!"表徵圖)。
總結
這本篇文章裡面,我展示了Allocation Tracker和heap dumps是如何給你一種對程式記憶體使用量的感性認識。我也展示了Eclipse Memory Analyzer(MAT)可以協助追逐我們程式裡面的記憶體泄露問題。MAT是一個強大的工具,我也僅僅觸碰了一些皮毛,如果你想學習更多內容,我建議讀 一些下面的文章:
- Memory Analyzer News : Eclipse MAT project的官方部落格。
- Markus Kohler的Java Performance blog有很多有用的文章, 包括 Analysing the Memory Usage of Android Applications with the Eclipse
Memory Analyzer and 10 Useful Tips for the Eclipse Memory Analyzer .