Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android 內存洩漏

Android 內存洩漏

編輯:關於Android編程

 

 

Andriod應用的堆棧大小在T-Mobile G1上被限制在16MB,對於一個手機這已經是很大的內存了,但對一些開發者來說還是不夠。即使你不需要使用這麼多的內存空間,你也應該盡可能地節省使用,這樣就不至於在其他應用運行的時候將你的殺掉。Android可以在內存中緩存的應用越多,應用間的切換也就越流暢。作為我的一部分工作,我深入了解了Android應用內存洩漏問題,發現大多數都是同一類情況——長時間保持對一個Context的引用(keep a long_lived reference to a Context)。

在Android裡,許多操作都需要使用Context,但絕大部分情況是獲取、加載資源,這也是所有的控件需要在構造函數裡接收一個Context參數的原因。一般情況下,我們可以獲取兩種Context,Activity和Application,開發者通常會將第一個也就是Activity作為參數進行傳遞。

 

@Override
protected void onCreate(Bundle state) {
  super.onCreate(state);
  
  TextView label = new TextView(this);
  label.setText(Leaks are bad);
  
  setContentView(label);
}

這意味著view持有了整個Activity的引用和他裡面的所有東西,比如整個view hierarchy和所有的資源。因此,如果你洩漏了Context(“洩漏”的意思是你保持了他的引用,使得GC不能及時回收),你就洩漏了一大部分內存。如果不夠小心點話洩漏整個activity是很容易的。

 

當屏幕方向改變時系統會默認destroy當前的activity,保存當前狀態並創建一個新的activity,也就是Android會重新從資源文件中加載應用的視圖。想象一下你的應用裡有一幅大圖,但並不像每次旋轉屏幕都重新去加載,將它緩存在內存裡最簡單的辦法是將它聲明為static類型:

 

private static Drawable sBackground;

@Override
protected void onCreate(Bundle state) {
  super.onCreate(state);
  
  TextView label = new TextView(this);
  label.setText(Leaks are bad);
  
  if (sBackground == null) {
    sBackground = getDrawable(R.drawable.large_bitmap);
  }
  label.setBackgroundDrawable(sBackground);
  
  setContentView(label);
}

上面的代碼運行很快,但做法卻是錯誤的,當屏幕旋轉的時候洩漏了整個activity,當一個Drawable關聯到view上,這個view就被設置為drawable的一個callback,在上面的代碼裡,這意味著drawable保持了TextView的引用,而TextView又保持了整個Activity的引用,也就幾乎關聯了activity裡的所有東西。

 

這個例子是Context洩漏裡最簡單的一種情況,你可以在HomeScreen的源碼裡看我們是怎麼通過把drawable的callback設置為null來解決這個問題的(搜索unbindDrawables()方法),有趣的是,有時會創建出一條洩漏context的調用鏈,這樣會使你的內存更快的耗盡。
有兩種簡單的方式來避免context相關的內存洩漏,一個是避免context逃出他自己的范圍(avoid escaping the context outside of its own scope),上面的例子展示了靜態引用造成洩漏的情況,但是內部類對外部類的強引用也同樣危險。另一種解決方法是使用Application context,這個context會一直存在,直到你的應用退出,而不會依賴於activity的生命周期。如果你有一個長時間存活的對象,而且對象有context的引用,記住使用application context,這個你可以很容易地通過Context.getApplicationContext()或者Activity.getApplication()來獲取。
總之,避免context相關的內存洩漏,記得下面幾條
不要保持長時間對activity context類型的引用(一個對activity的引用應該和這個activity有相同的生命周期)使用application context而不是activity context避免在一個activity中使用非靜態(non-static)內部類,如果你不管他的生命周期的話,使用一個靜態內部類,然後在這個類內部維持一個對activity的弱引用,就像在ViewRoot類中的W內部類這樣。垃圾回收不保證內存洩漏
  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved