1. 程式人生 > >Android記憶體洩漏8種可能及完善解決方案

Android記憶體洩漏8種可能及完善解決方案

借鑑自https://www.jianshu.com/p/ac00e370f83d

一般記憶體洩漏(traditional memory leak)的原因是:由忘記釋放分配的記憶體導致的。(Cursor忘記關閉等)
邏輯記憶體洩漏(logical memory leak)的原因是:當應用不再需要這個物件,當仍未釋放該物件的所有引用。

如果持有物件的引用,垃圾回收器是無法回收這個物件的。但是並不是說,引用被別人持有了,就是記憶體洩漏了。比如activity,你在用,那就不叫記憶體的洩漏,記憶體該花還是得花。但是當用戶跳轉到別的activity了,銷燬了之前的activity,這個時候,如果之前那個activity的資源還沒有被釋放這就說不過去了。最典型的原因是之前的activity的例項依然被另外的物件持有著。有些顯示的引用還好說,隱式的如內部類的引用,可就真的難以查出來了。

最典型的,靜態activity

private Activity activity = null;
public void setActivity(Activity activity) {
    this.activity = activity;
}
這個類一旦被載入了,那麼好了,從現在開始,到整個應用結束,這個activity的例項一直就被維護在這裡了。怎麼解決?你得注意在Activity的onDestory裡釋放他啊。此外,不僅僅是靜態的activity,靜態的佔大記憶體的資源比如View,也有記憶體大面積洩漏的危險,也需要進行一個釋放。

(維護成弱引用也行,如private static WeakReference<MainActivity> activityReference)

內部類(async task、handler、runnable、thread、timer task等等,只要是非靜態內部類+可能延時的都會啊)

不管是匿名的還是非靜態的內部類,都會持有外部類的強引用。如果你這個內部類是handler,runnable等,就危險了,因為message的target會持有handler的引用,message的callback會持有runnable的引用,而runnable、handler又會隱式持有activity的例項,所以這一串鏈式呼叫上的所有例項都不會被釋放,boom。還有正常的內部類(不延時的)也會出現問題,當你把這個內部類宣告成靜態成員變數的時候。這個時候靜態的是不會被銷燬的,所以內部類不會被銷燬,而內部類會隱式持有activity的例項,這個時候也記憶體洩漏了。

(解決方式請看:Android Handler、非靜態、匿名內部類的記憶體洩漏,用靜態內部類+弱引用或handler.removeCallbackAndMessages(null)http://blog.csdn.net/qq_36523667/article/details/78945778)

Sensor Manager

通過Context.getSystemService(int name)可以獲取系統服務。這些服務工作在各自的程序中,幫助應用處理後臺任務,處理硬體互動。如果需要使用這些服務,可以註冊監聽器,這會導致服務持有了Context的引用,如果在Activity銷燬的時候沒有登出這些監聽器,會導致記憶體洩漏。