首頁>技術>

背景

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

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

洩露場景臨時性記憶體洩漏

1.context引用

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

2.非靜態內部類

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

3.匿名類

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

4.監聽器

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

5.資源物件未關閉

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

6.不要在執行頻率高的方法中建立物件

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

7.WebView造成的洩露

當我們不要使用WebView物件時,應該呼叫它的destory()函式來銷燬它,並釋放其佔用的記憶體,否則其佔用的記憶體長期也不能被回收,從而造成記憶體洩露。

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銷燬的時候,沒有登出掉監聽器,就會導致記憶體洩漏。

解決方法弱引用(耗時操作持有的context等引用可以用弱引用)使用LeakCanary工具查詢記憶體洩漏(該工具會會自動分析context是否引起記憶體洩漏)Android Studio自帶分析工具Profiler(使用該工具可以實時檢視記憶體使用狀況)

最新評論
  • BSA-TRITC(10mg/ml) TRITC-BSA 牛血清白蛋白改性標記羅丹明
  • APICloud年終盤點|種下一粒種子,書寫一份未來