Android內存洩露終級無敵之透徹分析


Android內存洩露終級無敵之透徹分析

背景

Java是垃圾回收語言的一種,其優點是開發者無需特意管理內存分配,降低了應用由於局部故障導致崩潰,同時防止未釋放的內存把堆棧(heap)擠爆的可能,所以寫出來的代碼更為安全。


不幸的是,在Java中仍存在很多容易導致內存洩漏的邏輯可能。如果不小心,你的Android應用很容易浪費掉未釋放的內存,輕則應用卡頓,重則導致內存用光拋出OOM。

洩露場景

  • 臨時性內存洩漏

1.context引用

context引用 況會持有外部類的引用,一旦執行耗時操作,會造成內存回收不及時,從而造成OOM。典型例子就是Handler,當Handler聲明為非靜態內部類時會持有外部類(例如Activity)的引用。

2.非靜態內部類

這種情況會持有外部類的引用,一旦執行耗時操作,會造成內存回收不及時,從而造成OOM。典型例子就是Handler,當Handler聲明為非靜態內部類時會持有外部類(例如Activity)的引用。


Android內存洩露終級無敵之透徹分析


3.匿名類

相似地,匿名類也維護了外部類的引用。所以內存洩漏很容易發生,當你在Activity中定義了匿名的AsyncTsk。當異步任務在後臺執行耗時任務期間,Activity不幸被銷燬了,這個被AsyncTask持有的Activity實例就不會被垃圾回收器回收,直到異步任務結束。


Android內存洩露終級無敵之透徹分析


4.監聽器

App開發中我們都需要和監聽器打交道,通常一個應用當中會用到很多監聽器,我們會調用一個控件的諸如addXXXListener()等方法來增加監聽器,但往往在釋放對象的時候卻沒有記住去刪除這些監聽器,一旦監聽器裡執行了耗時操作,對象就無法回收,從而增加了內存洩漏的機會。

5.資源對象未關閉

資源性對象比如(Cursor遊標,Stream流,BroadCastReceiver等)往往都用了一些緩衝,我們在不使用的時候或者在使用完之後,應該及時關閉它們比如close()方法,以便它們的緩衝及時回收內存。Bitmap要先recyler(),在置為null。

6.不要在執行頻率高的方法中創建對象

在自定義View中onDraw和onMesaure這兩個方法一般執行頻率很高,一旦使用不當,會創建大量對象,頻繁GC,會導致應用變卡頓。

7.WebView造成的洩露

當我們不要使用WebView對象時,應該調用它的destory()函數來銷燬它,並釋放其佔用的內存,否則其佔用的內存長期也不能被回收,從而造成內存洩露。


Android內存洩露終級無敵之透徹分析


8.構造Adapter時,沒有使用緩存的ConvertView

ListView在加載佈局時如果不使用緩存的ConvertView,而是每次重新加載,就容易造成內存洩漏,應用卡頓。

  • 永久性內存洩漏

1.全局變量

全局變量的內存永遠不會被回收,一般app中都會定義一個常量類來存放這些數據,但是能少用全局變量就少用,畢竟要一直佔用內存,如果使用建議只存儲一些基本數據類型,切記不要持有context,activity,fragment,view的引用。這種錯誤一般在單例模式中比較常見。

2.屬性動畫

從Android3.0開始,Google提供了屬性動畫,屬性動畫中有一類無限循環的動畫,如果在Activity中播放此類動畫並且在onDestroy()方法中沒有停止該動畫,那麼動畫會一直循環下去,儘管在界面上已經無法看不到動畫了,但這個時候Activity的View會被動畫持有,而View又持有Activity,最終Activity無法釋放。

3.系統服務

當你使用系統服務的時候,可以註冊監聽器,會導致服務持有Context的引用,如果在Activity銷燬的時候,沒有註銷掉監聽器,就會導致內存洩漏。


Android內存洩露終級無敵之透徹分析

解決方法

  • 弱引用(耗時操作持有的context等引用可以用弱引用)
  • 使用LeakCanary工具查找內存洩漏(該工具會會自動分析context是否引起內存洩漏)
  • Android Studio自帶分析工具Profiler(使用該工具可以實時查看內存使用狀況)


Android內存洩露終級無敵之透徹分析


分享到:


相關文章: