Dalvik虛擬機(jī)支持垃圾收集,但是這不意味著你可以不用關(guān)心內(nèi)存管理。你應(yīng)該格外注意移動(dòng)設(shè)備的內(nèi)存使用,在上面內(nèi)存空間是受到限制的。在這篇文章里面,我們來看看Android SDK里面的一些內(nèi)存剖析工具(profiling tools)是如何幫助我們修整應(yīng)用程序的內(nèi)存使用。 必要的工具:
分析heap dump,你可以使用一些標(biāo)準(zhǔn)的工具比如jhat 或者Eclipse Memory Analyzer(MAT) 。不過,首先你需要把.hprof文件從Dalvik格式轉(zhuǎn)換成J2SE HPROF格式。你可以使用Android SDK提供的hprof-conv工具。例如:
調(diào)試一個(gè)內(nèi)存泄露實(shí)例:
我們來過一個(gè)實(shí)際的例子,Android SDK里面提供的范例程序Honeycomb Gallery sample app 。它是一個(gè)photo gallery程序,用來演示一些新的Honeycomb API的使用。(下載和編譯這些代碼,請(qǐng)看這些命令 。)我們會(huì)有意地加入一個(gè)內(nèi)存泄露在程序里邊,然后來演示如何調(diào)試它。
這里就是我們保存緩存的地方?,F(xiàn)在我們可以修改updateContentAndRecycleBitmap()方法,讓它在下載之前先查看是否數(shù)據(jù)已經(jīng)存在,如果不存在就去下載,然后添加數(shù)據(jù)到緩存。
我已經(jīng)在這里故意引入了一個(gè)內(nèi)存泄露的問題:我們把圖片加入了緩存但是從來沒有移除他們。在真實(shí)的應(yīng)用里,我們可以會(huì)用某種方法來限制緩存的大小。 在DDMS里檢查heap的使用情況 Dalvik Debug Monitor Server(DDMS)是主要的Android調(diào)試工具之一,也是ADT Eclipse plug-in 的一部分,獨(dú)立的程序版本也可以在Android SDK的根目錄下的tools/下面找到。關(guān)于DDMS更多的信息,請(qǐng)參考使用DDMS 。 我們來使用DDMS檢查這個(gè)應(yīng)用的heap使用情況。你可以使用下面的兩種方法啟動(dòng)DDMS:
在左邊的面板選擇進(jìn)程com.example.android.hcgallery,然后在工具條上邊點(diǎn)擊Show heap updates按鈕。這個(gè)時(shí)候切換到DDMS的VM Heap分頁。它會(huì)顯示每次gc后heap內(nèi)存的一些基本數(shù)據(jù)。要看第一次gc后的數(shù)據(jù)內(nèi)容,點(diǎn)擊Cause GC按鈕: 我們可以看到現(xiàn)在的值(Allocated列)是有一些超過8MB?,F(xiàn)在滑動(dòng)相片,這時(shí)看到數(shù)據(jù)在增大。因?yàn)橹挥袃H僅13個(gè)相片在程序里邊,所以泄露的內(nèi)存只有這么大。在某種程度上來說,這時(shí)最壞的一種內(nèi)存泄露,因?yàn)槲覀儧]法得到 OutOfMemoryError來提醒我們說現(xiàn)在內(nèi)存溢出了。 生成heap dump 我們現(xiàn)在使用heap dump來追蹤這個(gè)問題。點(diǎn)擊DDMS工具條上面的Dump HPROF文件按鈕,選擇文件存儲(chǔ)位置,然后在運(yùn)行hprof-conv。在這個(gè)例子里我們使用獨(dú)立的MAT版本(版本1.0.1),從MAT站點(diǎn)下載 。 如果你使用ADT(它包含DDMS的插件)同時(shí)也在eclipse里面安裝了MAT,點(diǎn)擊“dump HPROF”按鈕將會(huì)自動(dòng)地做轉(zhuǎn)換(用hprof-conv)同時(shí)會(huì)在eclipse里面打開轉(zhuǎn)換后的hprof文件(它其實(shí)用MAT打開)。 用MAT分析heap dumps啟動(dòng)MAT然后加載剛才我們生成的HPROF文件。MAT是一個(gè)強(qiáng)大的工具,講述它所有的特性超出了本文的范圍,所以我只想演示一種你可以用來檢測(cè)泄露的方法:直方圖(Histogram)視圖。它顯示了一個(gè)可以排序的類實(shí)例的列表,內(nèi)容包括:shallow heap(所有實(shí)例的內(nèi)存使用總和),或者retained heap(所有類實(shí)例被分配的內(nèi)存總和,里面也包括他們所有引用的對(duì)象)。 如果我們按照shallow heap排序,我們可以看到byte[]實(shí)例在頂端。自從Android3.0(Honeycomb),Bitmap的像素?cái)?shù)據(jù)被存儲(chǔ)在byte數(shù)組里(之前是被存儲(chǔ)在Dalvik的heap里),所以基于這個(gè)對(duì)象的大小來判斷,不用說它一定是我們泄露掉的bitmap。 右擊byte[]類然后選擇List Objects > with incoming references。它會(huì)生成一個(gè)heap上的所有byte數(shù)組的列表,在列表里,我們可以按照Shallow Heap的使用情況來排序。 選擇并展開一個(gè)比較大的對(duì)象,它將展示從根到這個(gè)對(duì)象的路徑--就是一條保證對(duì)象有效的鏈條。注意看,這個(gè)就是我們的bitmap緩存! MAT不會(huì)明確告訴我們這就是泄露,因?yàn)樗膊恢肋@個(gè)東西是不是程序還需要的,只有程序員知道。在這個(gè)案例里面,緩存使用的大量的內(nèi)存會(huì)影響到后面的應(yīng)用程序,所以我們可以考慮限制緩存的大小。 使用MAT比較heap dumps 調(diào)試內(nèi)存泄露時(shí),有時(shí)候適時(shí)比較2個(gè)地方的heap狀態(tài)是很有用的。這時(shí)你就需要生成2個(gè)單獨(dú)的HPROF文件(不要忘了轉(zhuǎn)換格式)。下面是一些關(guān)于如何在MAT里比較2個(gè)heap dumps的內(nèi)容(有一點(diǎn)復(fù)雜):
總結(jié) 這本篇文章里面,我展示了Allocation Tracker和heap dumps是如何給你一種對(duì)程序內(nèi)存使用的感性認(rèn)識(shí)。我也展示了Eclipse Memory Analyzer(MAT)可以幫助追逐我們程序里面的內(nèi)存泄露問題。MAT是一個(gè)強(qiáng)大的工具,我也僅僅觸碰了一些皮毛,如果你想學(xué)習(xí)更多內(nèi)容,我建議讀一些下面的文章:
|
|