2014年6月26日木曜日

[安藤]android bitmap的回收處理跟記憶體分析

Android程式設計一個困擾了我很久的地方,就是大量用圖卻沒有正確釋放的時候所產生的out of memory error。
一個bitmap drawable若是被設定在ImageView上面,就算是該ImageView object已經不出現在畫面上,甚至是該Activity已經被destory, drawable還是不會被GC。這個特性直到現在都還是存在。

好不容易實作個精美又圖文並茂的ListView或是viewpager的時候,
上下左右滑個沒幾次,out of memory exception隨之出現。

這裡要來談談一些對策。
解決方案只有一條:「每一個View在沒用到的時候,被設定在上面的bitmap drawable都要被斷開」。用Layer Drawable內包bitmap也需要注意,必須把使用bitmap的那一層給移掉,bitmap drawable才會被自動GC。

當你的Layout上面的ImageView都是使用xml定義的時候,很簡單。
findViewById()一個個抓出ImageView的object,然後執行imageview.setImageDrawable(null)。

ViewPager也簡單。在PagerAdapter裡面的
public void destroyItem(View arg0, int arg1, Object arg2) { }
實作取得ImageView的動作,並執行imageview.setImageDrawable(null)。
要釋放所有的圖的時候,執行viewpager.setadapter(null)即可。
因為各個Pager頁面的PagerAdapter.destroyItem()在執行viewpager.setadapter(null)的時候一定會執行。


ListView...最麻煩的來了。
雖然可以設定RecyclerListener,捲動時的回收問題解決了,但是
執行ListView.setAdapter(null),會發現RecyclerListener一動也不動。
所以遇到ListView的話,在設定你的新adapter或是destroy activity之前,乖乖的把cell裡面的ImageView一個個抓出來執行setImageDrawable(null)吧。


以上是比較明顯好處理的部份。接下來要談談不好處理的部份,就是一點一滴累積出來的
memory leak。在你認為java應該要幫你釋放的時候,它卻永存於記憶體。

Eclipse有提供一個好用的記憶體分析的工具:Memory Analyzer。
很慶幸的,ADT裡面也可以用它。在這裡簡單介紹一下使用步驟。(本例的ADT是2014/03/21的版本。)

===============================

首先得安裝它。從ADT視窗上方的Help選項裡面,有個「Install Softwares」,點選後出現以下視窗。然後在視窗的work with輸入區裡面輸入「http://download.eclipse.org/releases/kepler」

點選「Add」,然後等待系統取得安裝包的列表,就可以看到Memory Analyzer了。圖上是已經裝好的狀態。

接著,照一般開發流程使用ADT debug需要觀察的app,隨便下個斷點,等app執行到斷點或是手動pause皆可。ADT通常會切換到DDMS perspective,這時可以看到task的區塊。

點選你要dump記憶體的task,然後點選上圖那隻淺綠色蟲的右邊的icon「update heap」,再點一下旁邊的「dump HPROF file」。等上一陣子,就會出現一個wizard。若是沒出現wizard的話,有可能是設定成把HPROF存檔了。請到ADT的Preferences->Android->DDMS->HPROF Action設定為「Open in Eclipse」。


看到wizard,總之先選「Leak Suspects Report」。它會出一個餅圖,還會幫忙判斷哪個東西佔最多記憶體。



以下是出現的餅圖。餅圖下面會有些黃色框框,列出一些可能的問題點。
點開「Details」就可以看到整理好的Object等等的東西。

圖的上方,被藍色標起來的「Leak suspects」就是wizard提供的功能。
要是wizard忘記點選,而又需要看餅圖的話可以用此法再開一次。
「Top components」會幫忙測試哪個Object重複或是類似的東西出現最多次,對於記憶體使用狀況的判斷也相當有用。


假如是灰色的部份佔去最多記憶體的話,代表這些佔記憶體的物件被掛在List/Map等等不會被清除的資料結構裡面。也許需要一個整理List/Map的機制。


0 件のコメント:

コメントを投稿