Android 避免內存泄漏(譯)

(轉) app

 

Android應用程序的內存被限定在16MB,至少在G1手機上是這樣。對於一個手機來講,這已經佔用了很是多的內存了,可是對於開發者想要實現的目標而言,這些內存是很是少的。即時你原本就沒打算用掉全部的內存,可是你應該儘量的少用內存,來讓其餘程序能夠保持運行,而不是被系統殺掉。系統在內存裏保存的應用程序越多,用戶在應用程序之間選擇切換的速度就會越快。做爲我工做的一部分,我跟蹤了Android應用程序內存泄露的狀況,發現它們大多數是由於同一個問題:保持了對Context對象的長期的引用。 

在Android系統上,不少操做都用到了Context對象,可是大多數都是用來加載和訪問資源的。這就是爲何全部的顯示控件都須要一個Context對象做爲構造方法的參數。在Android應用程序中,你一般可使用兩種Context對象,Activity和Application。當類或者方法須要Context對象的時候,開發者一般會用第一個做爲參數。 
@Override 
protected void onCreate(Bundle state) { 
  super.onCreate(state); 
  
  TextView label = new TextView(this); 
  label.setText("Leaks are bad"); 
  
  setContentView(label); 

這就意味着,View對象對整個activity保持引用,所以,也就保持對activity內的全部東西的引用;一般是整個View結構和它全部的資源。因此,若是你一直保持着對Activity的引用,你佔用了不少內存。在你不注意的時候,你很容易就持有對activity的長期引用。 
當屏幕方向改變時,默認的,系統會摧毀當前的activity,而後建立一個新的activity,這個新的activity會顯示剛纔的狀態。在這樣作的過程當中,Android系統會從新加載UI用到的資源。如今假設你的應用程序中有一個比較大的bitmap類型的圖片,然而你不想每次旋轉時都從新加載它。 
保持屏幕旋轉,又不讓它從新加載,最簡單的方法是用靜態變量的方法。 
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對象的一個回調(引用)。在上面的代碼片斷中,就意味着drawable和TextView存在着引用的關係,而TextView本身引用着activity(Context對象),這個activity又引用着至關多的東西。 
這個例子就是很是簡單的泄露Context對象的一種狀況,你能夠在「 Home screen's source code( unbindDrawables()方法)」中看到是如何作的,當activity被摧毀時,設置drawable的回調(引用)爲null。使人感興趣的是,有不少種狀況,你會建立出一個泄露context對象的鏈,它們是糟糕的。它們會很快耗光內存,使你的內存溢出。 

有兩種簡單的方法能夠避免由引用context對象形成的內存泄露。最明顯的一個方法是,避免context對象超出它的做用範圍。上面的例子顯展現了靜態引用的狀況,可是在類的內部,隱式的引用外部的類一樣的危險。第二種方法是,使用Application對象。這個context對象會隨着應用程序的存在而存在,而不依賴於activity的生命週期。若是你打算對context對象保持一個長期的引用,請記住這個application對象。經過調用Context.getApplicationContext() 或者 Activity.getApplication().方法,你能夠很容易的獲得這個對象。 

總之,要避免因爲引用context對象形成的內存泄露,記住如下幾點: 

不要保持對activity的持久引用(對activity的引用應該和activity自己有相同的生命週期) 
儘可能使用application代替activity 
若是不能控制非靜態的內部類的生命週期,儘可能在activity中避免有非靜態的內部類,在activity中使用靜態的類,要對activity保持弱引用。 
垃圾回收器並不能保證阻止內存泄露
ide

相關文章
相關標籤/搜索