閱讀716 返回首頁    go 阿裏雲 go 技術社區[雲棲]


Android應用內存泄露分析、改善經驗總結

前言

通過這幾天對好幾個應用的內存泄露檢測和改善,效果明顯:

  • 完全退出應用時,手動觸發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的Analyz

-Inspect Code對代碼做靜態分析,常見的內存泄露問題有:

  • 非靜態內部類導致的內存泄露,比如Handler,解決方法是將內部類寫成靜態內部類,在靜態內部類中使用軟引用/弱引用持有外部類的實例,eg:
  • IO操作後,沒有關閉文件導致的內存泄露,比如Cursor、FileInputStream、FileOutputStream使用完後沒有關閉,這種問題在Android Studio 2.0中能夠通過靜態代碼分析檢查出來,直接改善就可以了;
  • 自定義View中使用TypedArray後,沒有recycle,這種問題也可以在Android Studio 2.0中能夠通過靜態代碼分析檢查出來,直接改善就可以了;
  • 某些地方使用了四大組件的context,在離開這些組件後仍然持有其context導致的內存泄露,這種問題屬於共識,在編寫代碼的過程中就應該按照規則來,使用Application的Context就可以解決這類內存泄露的問題了,至於什麼情況下應該使用四大組件的Context,什麼時候應該使用Application的context可以參見下表:

application使用場景

備注:大家注意看到有一些NO上添加了一些數字,其實這些從能力上來說是YES,但是為什麼說是NO呢?下麵一個一個解釋:

  • 還有一種不屬於內存泄露,但在分析內存泄露的問題時應該一並解決:同一個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分析,周而複始,改善到自己滿意為止。  

 阿裏雲測移動質量中心(以下簡稱MQC)是為廣大企業客戶和移動開發者提供真機測試服務的雲平台,擁有大量熱門機型,提供7x24全天候服務。
       
我們致力於提供專業、穩定、全麵、高價值的自動化測試能力,以及簡單易用的使用流程、貼心的技術服務,並且幫助客戶以最低的成本、最高的效率發現APP中的各類隱患(APP崩潰、各類兼容性問題、功能性問題、性能問題等),減少用戶流失,提高APP質量和市場競爭力。

聯係我們:
 網站地址:https://mqc.aliyun.com
 開發者交流旺旺群:335334143
 開發者交流QQ群:492028798
 客服郵箱:mqc_group@service.alibaba.com
更多精彩技術分享 歡迎關注 MQC公眾號
17

最後更新:2017-08-13 22:42:59

  上一篇:go  致力於操縱總統選舉的黑客
  下一篇:go  在一些歐洲市場Windows 10已經準備超越Windows 7