【編者按】本文做者爲來自南非約翰內斯堡的女程序員 Rebecca Franks,Rebecca 熱衷於安卓開發,擁有4年安卓應用開發經驗。有點完美主義者,喜好美食。html
本文系國內ITOM管理平臺 OneAPM 編譯呈現,如下爲正文。java
Android 程序中很容易出現內存泄露問題。毫無戒心的開發者可能天天都會形成一些內存泄露,卻不自知。你可能從未注意過這類錯誤,或者甚至都不知道它們的存在。直到你遇到下面這樣的異常:android
java.lang.OutOfMemoryError: Failed to allocate a 4308492 byte allocation with 467872 free bytes and 456KB until OOM at dalvik.system.VMRuntime.newNonMovableArray(Native Method) at android.graphics.BitmapFactory.nativeDecodeAsset(Native Method) at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:609) at android.graphics.BitmapFactory.decodeResourceStream(BitmapFactory.java:444) at android.graphics.drawable.Drawable.createFromResourceStream(Drawable.java:988) at android.content.res.Resources.loadDrawableForCookie(Resources.java:2580) at android.content.res.Resources.loadDrawable(Resources.java:2487) at android.content.res.Resources.getDrawable(Resources.java:814) at android.content.res.Resources.getDrawable(Resources.java:767) at com.nostra13.universalimageloader.core.DisplayImageOptions.getImageOnLoading(DisplayImageOptions.java:134)
啥?這是什麼意思?是說個人位圖(bitmap)太大了嗎?程序員
不幸的是,這種堆棧跟蹤每每帶點迷惑性。一般,若是遇到 OutOfMemoryError 錯誤,十有八九是由於內存泄露。當筆者第一次遇到這種堆棧跟蹤時,也感到疑惑不解,想着是否是位圖太大了……實際上,我那會兒真是大錯特錯。性能優化
內存泄露是指程序釋放廢棄內存失敗,致使性能受損或出現中斷。網絡
Android 程序中的內存泄露很容易產生,這也是問題的一部分。然而,最大的問題在於 Android Context(上下文) 對象。app
每一個 app 都有一個全局的應用上下文對象( getApplicationContext()
)。每一個 Activity (活動)都是 Context
的子類,存儲着與當前活動相關的信息。一般,內存泄露都與已泄露的活動(leaked activtiy)相關。eclipse
一般,通常的開發者會把上下文對象(context object)傳給須要的線程。建立一些靜態的 TextViews 以存儲指向活動的引用。可是,你懂的,這樣可行嗎?異步
在此狀況下,若是使用內存監視器就會發現,app 的內存使用率不斷增長,正以下面的 Android 內存監控器所示:ide
存在內存泄露問題的 app 在運行時,Android 內存監控器的狀況
解決內存泄露問題後,Android 內存監控器的狀況
如你所見,在第一張圖中,app 永遠都沒法回收一部分已經使用的內存。在 OutOfMemoryError 錯誤出現以前,它一度使用了300MB的內存。而第二張圖則顯示,app 能順利進行垃圾回收,重得一部份內存,從而保持至關穩定的內存使用量。
避免在 activity 或 fragment 以外傳遞 Context 對象。
永遠永遠不要建立靜態的 Context 或 View 對象,或者將兩者存儲於靜態變量中。這是內存泄露的首要標誌。
private static TextView textView; //DO NOT DO THIS
private static Context context; //DO NOT DO THIS
老是記得在 onPause() 或 onDestroy() 方法中的取消註冊監聽器(listeners)。這包括 Android
監聽器,以及位置服務、顯示管理器服務,還有自定義的一些監聽器。
不要在 AsyncTasks(異步任務)或後臺線程中存儲指向 activities 的強引用。Activity 可能會關閉,可是
AsyncTask 會繼續執行,一直保存着對該 activity 的引用。
若是能夠,使用 Context-application (getApplicationContext()),而不是某個 activity
的 Context 對象。
盡力避免使用非靜態的內部類。將引用存儲至某個 Activity 或 View 內部會致使內存泄露。若是不得不存儲引用,請使用
WeakReference。
修復內存泄露問題須要許多實踐,不斷嘗試、試錯,才能取得成功。一般,內存泄露並不容易定位。值得慶幸的是,有許多現成的工具能夠幫你找出潛在的泄露問題。
一、打開 Android Studio,打開 Android Monitor(監控器)選項。
二、運行你的應用,從可選應用中進行選擇你的應用,並運行之。
三、在 app 中進行一些操做,以達到相似的效果。譬如筆者,打開了一個新視頻,播放了50次。(爲此,筆者寫了一個測試程序。)
四、此處的關鍵,是在出現 OutOfMemoryException 異常以前捕獲應用的問題。
五、點擊 Android 監控器中的內存選項。
六、你會看到一張動態繪製的圖表。準備好以後,點擊「啓動垃圾回收(Initiate GC)「(紅色的垃圾卡車圖標)。
七、點擊「傾倒 Java 堆內存(Dump Java Heap)」,以後等待數秒。(卡車圖標下面帶有綠色箭頭的圖標)。這會生成一個 .hprof 文件,你能夠用來分析內存使用率。
八、不幸的是,Android Studio Hprof 文件查看器不具有 Eclipse 內存分析器的全部小工具。所以,你須要安裝 MAT。
九、運行下面的指令,將 Android 的 .hprof 文件轉換爲 MAT 可以理解的格式。(hprof-conv 工具位於 sdk 的平臺工具文件夾下)
./hprof-conv path/file.hprof exitPath/heap-converted.hprof
十、轉換完成後,在 MAT 中打開該文件。選擇「泄露疑點報告(Leak Suspects Report)」,以後點擊完成。
打開 Eclipse 內存分析器 —— 選擇泄露疑點報告
十一、點擊頂部的三個藍色柱形圖標,「爲任意對象集合建立一個直方圖」。你會看到佔用內存的一列對象。
Eclipse 內存分析器 — 直方圖
十二、查看這麼多對象或許會讓人摸不到頭腦。其實,你能夠根據類名進行過濾,所以筆者建議你在類名過濾器中輸入類名。
查找並修復Android中的內存泄露—OutOfMemoryError 技術分享 第6張根據類名在 Eclipse 內存分析器中過濾對象
1三、如今,咱們看到 VideoDetailActivity
存在9個實例。這顯然是不對的,由於咱們其實只須要一個。進一步查看誰保存着 VideoDetailActivity
的引用,右鍵點擊該項目,選擇「合併垃圾回收根的最短路徑(Merge Paths to Shortest GC Root)」,而後點擊「排除全部虛/弱/軟引用(exclude all phantom/weak/soft etc. references)。」
Eclipse 內存分析器——合併垃圾回收根的最短路徑
如今,保存着引用的線程就會顯示出來。以後,你能夠追根溯源,找到存儲該 activity 引用的具體實例。
1四、根據下面的信息,顯然,有一個 DisplayListener 對象在登記以後從未註銷過。
Eclipse 內存分析器 — 內存泄露識別
所以,對這個此前登記的顯示監聽器(display listener)調用註銷方法,就能解決此內存泄露問題。
DisplayManager displayManager = (DisplayManager) mContext.getSystemService(Context.DISPLAY_SERVICE);displayManager.unregisterDisplayListener(listener);
不過,並不是全部的內存泄露都這麼容易找到,也有一些很是難找。可是,但願本文能使你開始尋找問題根源,並避免潛在的內存泄露問題。此外,還有許多有助於尋找內存泄露問題的工具,點擊此處進行查看。
參考連接:
OneAPM Mobile Insight 以真實用戶體驗爲度量標準進行 Crash 分析,監控網絡請求及網絡錯誤,提高用戶留存。訪問 OneAPM 官方網站感覺更多應用性能優化體驗,想閱讀更多技術文章,請訪問 OneAPM 官方技術博客。
本文轉自 OneAPM 官方博客
原文地址:http://riggaroo.co.za/fixing-memory-leaks-in-android-outofmemoryerror/