Android 記憶體洩露優化處理
參考:
Android應用記憶體洩露分析、改善經驗總結
使用新版Android Studio檢測記憶體洩露和效能
解決安卓CPU使用率過高問題
Android CPU使用過大的問題解決以及造成的原因
AndroidStudio CPU Monitor使用介紹
Skipped 60 frames! The application may be doing too much work on its main thread
前言:
通過這幾天對好幾個應用的記憶體洩露檢測和改善,效果明顯:
完全退出應用時,手動觸發GC,從原來佔有記憶體100多M降到低於20M;
手動觸發GC後,通過adb shell dumpsys meminfo packagename -d檢視Activity和View的數量也趨近於0了(沒有做到歸零是因為SDK中存在記憶體洩露,需要中間層去處理);
發現了一個SDK中的記憶體洩露(Android InputMethodManager 導致的記憶體洩露及解決方案);
發現一個MTK Webview的記憶體洩露(org.chromium.android_webview.AwPasswordHandler.java中private static AwPasswordHandler sInstance = null導致的記憶體洩露)。
從結果來看我分析和改善記憶體洩露的方法是對的,這個過程並不複雜,所以可以梳理總結出來作為分享。
原則
對於效能問題,分析和改善有必要遵循以下原則:
- 一切看資料說話,不能跟著感覺走,感覺哪有問題就去改,很有可能會適得其反;
- 效能優化是一個持續的過程,需要不斷地改善,不要想著一氣呵成;
- 對於效能問題,不一定必須要改善,受限於架構或者其它原因某些問題可能會很難改善,必須要先保證能用,再才考慮好用。
- 改善後一定要驗證,任何一個地方的改動都需要驗證,避免因為改善效能問題導致其它的問題。
步驟
下面是我在針對記憶體洩露這個效能問題上的解決步驟:
優先處理常見的記憶體洩露問題
首先解決常見的記憶體洩露問題,這個過程可以藉助Android Studio的Analyze-Inspect Code對程式碼做靜態分析,常見的記憶體洩露問題有:
- 非靜態內部類導致的記憶體洩露,比如Handler,解決方法是將內部類寫成靜態內部類,在靜態內部類中使用軟引用/弱引用持有外部類的例項,eg:
static class ExerciseHandler extends Handler{
private SoftReference<ExerciseActivity> exerciseActivitySoftReference = null;
public ExerciseHandler(ExerciseActivity exerciseActivity){
exerciseActivitySoftReference = new SoftReference<ExerciseActivity>(exerciseActivity);
}
@Override
public void handleMessage(Message msg) {
ExerciseActivity exerciseActivity = exerciseActivitySoftReference.get();
if(null != exerciseActivity){
super.handleMessage(msg);
switch (msg.what) {
case MSG_XX:
exerciseActivity.***;
break;
default:
break;
}
}
}
}
IO操作後,沒有關閉檔案導致的記憶體洩露,比如Cursor、FileInputStream、FileOutputStream使用完後沒有關閉,這種問題在Android Studio 2.0中能夠通過靜態程式碼分析檢查出來,直接改善就可以了;
自定義View中使用TypedArray後,沒有recycle,這種問題也可以在Android Studio 2.0中能夠通過靜態程式碼分析檢查出來,直接改善就可以了;
-
某些地方使用了四大元件的context,在離開這些元件後仍然持有其context導致的記憶體洩露,這種問題屬於共識,在編寫程式碼的過程中就應該按照規則來,使用Application的Context就可以解決這類記憶體洩露的問題了,至於什麼情況下應該使用四大元件的Context,什麼時候應該使用Application的context可以參見下表:
備註:大家注意看到有一些NO上新增了一些數字,其實這些從能力上來說是YES,但是為什麼說是NO呢?下面一個一個解釋:
數字1:啟動Activity在這些類中是可以的,但是需要建立一個新的task,一般情況不推薦;
數字2:在這些類中去layout inflate是合法的,但是會使用系統預設的主題樣式,如果你自定義了某些樣式可能不會被使用;
數字3:在Receiver為null時允許,在4.2或以上的版本中,用於獲取黏性廣播的當前值。(可以無視);
ContentProvider、BroadcastReceiver之所以在上述表格中,是因為在其內部方法中都有一個context用於使用。
還有一種不屬於記憶體洩露,但在分析記憶體洩露的問題時應該一併解決:同一個APP,將圖片放在不同的drawable資料夾下,在相同的裝置上佔用的記憶體情況不一樣,具體可以參見:關於Android中圖片大小、記憶體佔用與drawable資料夾關係的研究與分析。解決這個問題遵循以下原則就可以了:1、UI只提供一套高解析度的圖,圖片建議放在drawable-xxhdpi資料夾下(放在xxxhdpi或者更高解析度的資料夾下沒有必要,權衡利弊,照顧主流裝置即可),這樣在低解析度裝置中圖片的大小隻是壓縮,不會存在記憶體增大的情況;2、涉及到桌面外掛或者不需要縮放的圖片,放在drawable-nodpi資料夾下,這個資料夾下的圖片在任何裝置上都是不會縮放的。
通過工具檢查程式執行後的記憶體洩露
通過上面的步驟,應用中的大部分記憶體洩露問題都能夠得到解決,還有一些記憶體洩露,需要執行程式,分析執行後的記憶體快照來解決,比如註冊之後沒有反註冊、類中的靜態成員變數導致的記憶體洩露、SDK中的記憶體洩露等。解決這類問題可以分兩步進行:
- 通過記憶體洩露檢測工具先定位是哪有問題,記憶體洩露的檢測有兩種比較便捷的方式:1、一種是使用開源專案Leakcanary,需要新增到程式碼中,執行後生成分析結果;2、另一種方式是使用adb shell dumpsys meminfo packagename -d命令,在進入一個介面之前檢視一遍Activity和View的數量,在退出這個介面之後再檢視一遍Activity和View的數量,對比進入前和進入後Activity和View數量的變化情況,如果有差異,則說明存在記憶體洩露(在使用命令檢視Activity和View的數量之前,記得手動觸發GC)。
備註:在Android Studio中,可以通過如下方式獲取當前選中程式的記憶體資訊:
然後通過MAT取程式執行時的記憶體快照做詳細分析,對於MAT的使用,網上有很多優質的文章,比如:Android 效能優化之使用MAT分析記憶體洩露問題,在使用MAT前,有必要知道這幾點:1、 不要指望MAT明確告訴你哪裡存在記憶體洩露,這需要你根據上一步驟首先定位到可能存在記憶體洩露的類,然後藉助MAT確認是否真的存在記憶體洩露,具體哪個地方存在記憶體洩露;2、藉助Retained Size分析某一個類及與之相關的例項所消耗的記憶體,如果這個類的Retained Size比較大,優先分析;3、檢查某個類是否存在記憶體洩露時,排除其軟/弱/虛引用,右鍵某個類→Merge Shortest Paths to GC Roots→exclude all phantom/weak/soft etc.references。
驗證改善效果
根據個人經驗,我一般是這樣驗證改善效果的,執行程式,各個功能跑一遍,確保沒有改出問題,完全退出程式,手動觸發GC,然後通過adb shell dumpsys meminfo packagename -d檢視Activivites和Views的數量是否趨近於0;如果不是0,通過Leakcanary檢查可能存在記憶體洩露的地方,繼續通過MAT分析,周而復始,改善到自己滿意為止。
相關文章
- 如何處理 JavaScript 記憶體洩露JavaScript記憶體洩露
- Android記憶體優化——記憶體洩露檢測分析方法Android優化記憶體洩露
- 記憶體洩露例項分析 -- Android記憶體優化第四彈記憶體洩露Android優化
- 淺談Android開發中記憶體洩露與優化Android記憶體洩露優化
- win10驅動記憶體洩露如何解決_win10記憶體洩露處理方法Win10記憶體洩露
- Android效能優化篇之記憶體優化--記憶體洩漏Android優化記憶體
- 二、Android效能優化之記憶體洩露分析及工具使用Android優化記憶體洩露
- Android效能最佳化之記憶體洩露Android記憶體洩露
- Android 記憶體洩露詳解Android記憶體洩露
- Android 檢測記憶體洩露Android記憶體洩露
- 記憶體洩露記憶體洩露
- js記憶體洩露JS記憶體洩露
- JavaScript記憶體洩露JavaScript記憶體洩露
- 記憶體洩露嗎記憶體洩露
- SHBrowseForFolder 記憶體洩露記憶體洩露
- Android效能優化之記憶體洩漏Android優化記憶體
- Android 效能優化:手把手帶你全面瞭解記憶體洩露Android優化記憶體洩露
- Android 效能優化之記憶體洩漏檢測以及記憶體優化(上)Android優化記憶體
- Android 效能優化之記憶體洩漏檢測以及記憶體優化(下)Android優化記憶體
- Android 效能優化之記憶體洩漏檢測以及記憶體優化(中)Android優化記憶體
- Android記憶體優化(三)避免可控的記憶體洩漏Android記憶體優化
- 安卓效能優化之被忽視的記憶體洩露安卓優化記憶體洩露
- 處理Oracle記憶體洩露 ORA-00600 [729] [space leak]Oracle記憶體洩露
- android Handler導致的記憶體洩露Android記憶體洩露
- Android 如何避免 Context 記憶體洩露AndroidContext記憶體洩露
- Android中Handler引起的記憶體洩露Android記憶體洩露
- Android 中 Handler 引起的記憶體洩露Android記憶體洩露
- 記憶體溢位和記憶體洩露記憶體溢位記憶體洩露
- Lowmemorykiller記憶體洩露分析記憶體洩露
- 從記憶體洩露、記憶體溢位和堆外記憶體,JVM優化引數配置引數記憶體洩露記憶體溢位JVM優化
- 1.記憶體優化(一)記憶體洩漏記憶體優化
- Android記憶體洩露分析以及工具的使用Android記憶體洩露
- 使用 mtrace 分析 “記憶體洩露”記憶體洩露
- 實戰Go記憶體洩露Go記憶體洩露
- js記憶體洩露的原因JS記憶體洩露
- Java記憶體洩露的原因Java記憶體洩露
- JAVA 記憶體洩露的理解Java記憶體洩露
- IE中的記憶體洩露記憶體洩露