Android 避免內存泄漏

本文轉自:https://my.oschina.net/wpfjiayou1/blog/13159

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保持弱引用。 
垃圾回收器並不能保證阻止內存泄露
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章