1. 程式人生 > java教程 > Android中常見的記憶體洩漏 memory leak

Android中常見的記憶體洩漏 memory leak

四種主要的情況:


1、Activity物件未被回收


2、集合物件造成的洩漏


3、資源物件沒關閉造成記憶體洩漏


4、使用物件池避免頻繁建立物件


--------------------------------------------------------------------------------------


一. Activity物件未被回收


1.1 靜態變數引用Activity物件


通過靜態變數引用Activty物件時,會導致Activty物件所佔記憶體內漏。主要是因為,靜態變數是駐紮在JVM的方法區,因此,靜態變數引用的物件是不會被GC回收的。即最終導致Activity物件不被回收,從而也就造成記憶體洩漏。


Android中常見的記憶體洩漏memory leak_Java


看個簡單例子,比如說,你應用啟動Activty的場景很多,你希望定義一個工具類Util.Java,


在這個類中,定義一個啟動Activty的方法startActivity(Class nextActivity);以此來簡化啟動Activty的程式碼。


另外,加入你當前的Activty啟動另一個Activty的程式碼使用率也特別高。為了使得引數儘可能的少,你提供setFirstActivty,儲存當前的Activty。


在當前的Activty中,只需在onCreate中呼叫Util.setFirstActivity(this);,在需要啟動另一個Activty處呼叫Util.startActivity(SecondActivity.class);。


在上面程式碼中,如果當前的Activty不再使用 且Util中的sActivity物件沒有更改,會導致當前Activty一直駐留在記憶體中。


1.2 靜態View


有時,當一個Activity經常啟動,但是對應的View讀取非常耗時,我們可以通過靜態View變數來保持對該Activity的rootView引用。


但是要注意,一旦View attach到我們的Window上,就會持有一個Context(即Activity)的引用。


而我們的View有事一個靜態變數,所以導致Activity不被回收。但是在使用靜態View時,需要確保在資源回收時,將靜態View detach掉。


1.3 內部類

我們知道,非靜態內部類持有外部類的一個引用。因此,如果我們在一個外部類中定義一個靜態變數,這個靜態變數是引用內部類物件。將會導致記憶體洩漏!因為這相當於間接導致靜態引用外部類。


1.4 匿名類


Android中常見的記憶體洩漏memory leak_Java


1.5 Handler


Android中常見的記憶體洩漏memory leak_Java


在Java中,匿名內部類會引用外部類物件。而靜態內部類不會引用外部類物件.


這個mHandler會持有外部類(MainActivity)例項的引用,因為它處於一個物件的上下文中


1.6 Threads和TimerTask


Android中常見的記憶體洩漏memory leak_Java


Threads和Timer導致記憶體洩漏的原因跟內部類一樣。雖然在新的執行緒中建立匿名類,但是隻要是匿名類/內部類,它都會持有外部類引用.


這裡記憶體洩漏在於Timer和TimerTask沒有進行Cancel().


1.7 監聽器


Android中常見的記憶體洩漏memory leak_Java


當我們需要使用系統服務時,比如執行某些後臺任務、為硬體訪問提供介面等等系統服務。我們需要把自己註冊到服務的監聽器中。


然而,這會讓服務持有 activity 的引用,如果程式設計師忘記在 activity 銷燬時取消註冊,那就會導致 activity 洩漏了.在onDestroy方法裡登出監聽器。


---------------------------------------------------------------------------------------


2、集合物件造成的洩漏


當我們定義一個靜態的集合類時,請注意,這可能會導致記憶體洩漏!前面我們提到過,靜態變數所引用的物件是不會被回收掉的。而我的靜態集合類中,包含有大量的物件,這些物件不會被回收。另外,如果集合中儲存的物件又引用到了其他的大物件,如超長字串、Bitmap、大陣列等,很容易造成OOM。


---------------------------------------------------------------------------------------


3、資源物件沒關閉造成記憶體洩漏


當我們開啟資源時,一般都會使用快取。比如讀寫檔案資源、開啟資料庫資源、使用Bitmap資源等等。當我們不再使用時,應該關閉它們,使得快取記憶體區域及時回收。雖然有些物件,如果我們不去關閉,它自己在finalize()函式中會自行關閉。但是這得等到GC回收時才關閉,這樣會導致快取駐留一段時間。如果我們頻繁的開啟資源,記憶體洩漏帶來的影響就比較明顯了。


---------------------------------------------------------------------------------------


4、使用物件池避免頻繁建立物件


Android中常見的記憶體洩漏memory leak_Java


在我們需要頻繁建立使用某個類時,或者是在for迴圈裡面建立新的物件時,導致JVM不斷建立同一個類。


我們知道,在使用Message物件時,不是直接new出來的,而是通過obtain方法獲取,以及recycle方法回收。


這是典型的享元模式。我們可以通過使用物件池來實現.

主要原因:


長生命週期的物件持有短生命週期物件的引用就很可能發生記憶體洩露。