解決Android內存泄漏—輕松降低100M

背景

今天發現有個App存在嚴重的內存泄漏問題,通過安裝LeakCanary找到大致方向,通過嚴格管理Timer、Presenter和Handler,輕松把它消耗的內容降低了100M。

過程

LeakCanary

LeakCanary是square公司提供的一個很好用的內存泄漏查找工具,與MAT不同的是,它會在你運行App時檢查你的內存回收,并找到內存泄漏點,直接提示給你,比用MAT去分析日志的形式更加簡單直接,不過缺點是LeakCanary的信息不像MAT那么多,很難查到更細微的問題。

LeakCanary的安裝過程很簡單,首先配置Gradle

為LeakCanary添加Gradle引用

然后在自定義的Application中初始化

在自定義的MyApplication中初始化LeakCanary

記得在Manifest中使用自定義的Application

在AndroidManifest中使用自定義的MyApplication

運行App,LeakCanary會在App運行過程中不定期收集信息,如果發現有內存泄漏的問題,就會在通知欄中給出提示,如XXXActivity大概因為XXX泄露了XXM內存,比如我們運行LeakCanary在Github上的demo,得到的提示就會像下圖這樣

LeakCanary典型界面

可見,直接指出了問題類和問題原因,比起MAT還是簡單多了的

Timer

在檢查中,在Presenter里忘記關閉一個Timer的task,在Activity的onDestroy事件中調用Presenter的onDestroy

在Activity關閉時調用Presenter的銷毀函數

在Presenter的onDestroy中執行銷毀操作

在Presenter中的銷毀操作

我們看到,在Presenter銷毀元素時,做了三件事:

1.關閉線程(要先執行interrupt,否則休眠線程無法立即停止)

2.銷毀Presenter中關聯的View對象(否則會導致對應的Activity無法釋放)

3.退出Timer定時任務

Presenter

再看一遍Presenter執行銷毀操作的代碼

Presenter銷毀View

在上圖中,我們看到Presenter在銷毀時,一定要把View銷毀掉,否則會導致對應的Activity或Fragment無法釋放,在檢查中發現有些Presenter沒有寫銷毀,考慮在以后統一實現一個Presenter的基類,在基類中實現銷毀View的代碼

Handler

在檢查中,發現有些對話框彈出后無法回收內存,在檢查中發現了這樣的代碼

LeakHandler

這是我們一般接觸到的典型的Handler寫法,但是注意看提示,提示中說明了這里有泄漏風險,從避免內存泄漏的角度,應該改成這樣的代碼

AntiLeakHandler

在這段寫法中,我們用static內部類去重載了一個Handler,static內部類實際上會生成一個弱引用對象,這就不會產生內存泄漏。

不過這樣一來,在static內部類中,我們就無法調用Activity的函數了,這就需要在這個Handler初始化時把Activity傳進來,直接傳進來的Activity還是可能造成內存泄漏,我們還要把它放到一個弱引用對象里,通過get()函數取得Activity對象并調用其函數。

總結

在這次的內存泄漏查找過程中,主要解決了三個問題

1.及時銷毀所有的Timer定時任務

2.及時銷毀Presenter中的View對象

3.檢查所有的Handler,改為static+弱引用的實現方式

解決這些問題后,再次運行LeakCanary,已經不再輸出內存泄漏的內容了,App消耗的內存也減少了100多M。

其實這里解決的內存泄漏問題都是很淺顯的部分,能在這些地方出錯,說明這個App的內存泄漏已經相當嚴重了,在日常編碼中,還是要多留一份心才是。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容