Android 避免記憶體流失(譯)

來源:互聯網
上載者:User

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保持弱引用。
記憶體回收行程並不能保證阻止記憶體泄露

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.