Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android編程中避免內存洩露的方法總結

Android編程中避免內存洩露的方法總結

編輯:關於Android編程

Android的應用被限制為最多占用16m的內存,至少在T-Mobile G1上是這樣的(當然現在已經有幾百兆的內存可以用了——譯者注)。它包括電話本身占用的和開發者可以使用的兩部分。即使你沒有占用全部內存的打算,你也應該盡量少的使用內存,以免別的應用在運行的時候關閉你的應用。Android能在內存中保持的應用越多,用戶在切換應用的時候就越快。作為我的一項工作,我仔細研究了Android應用的內存洩露問題,大多數情況下它們是由同一個錯誤引起的,那就是對一個上下文(Context)保持了長時間的引用。

在Android中,上下文(Context)被用作很多操作中,但是大部分是載入和訪問資源。這就是所有的widget都會在它們的構造函數中接受一個上下文(Context)參數。在一個合格的Android應用中,你通常能夠用到兩種上下文(Context):活動(Activity)和應用(Application)。活動(Activity)通常被傳遞給需要上下文(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的層次和它的所有資源。因此,如果你“洩露”了上下文(Context)(這裡“洩露”的意思是你保持了一個引用並且組織GC收集它),你將造成大量的內存洩露。如果你不夠小心的話,“洩露”一整個活動(Activity)是件非常簡單的事情。

當屏幕的方向改變時系統會默認的銷毀當前的活動(Activity)並且創建一個新的並且保持了它的狀態。這樣的結果就是Android會從資源中重新載入應用的UI。現在想象一下,你寫了一個應用,有一個非常大的位圖,並且你並不想在每次旋轉時都重新載入。保留它並且每次旋轉不重新加載的最簡單的辦法就是把它保存在一個靜態字段上:
復制代碼 代碼如下:
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洩露的最簡單的一個原因,你可以看一下我們在主屏幕源碼(查看unbindDrawables()方法)中是通過在Activity銷毀時設置保存過的Drawable的回調為空來解決這個問題的。更為有趣的是,你可以創建一個context洩露的鏈,當然這非常的糟糕。它們可以讓你飛快的用光所有的內存。

有兩種簡單的方法可以避免與context相關的內存洩露。最明顯的一個就是避免在context的自身的范圍外使用它。上面的例子展示了在類內部的一個靜態的引用和它們對外部類的間接引用是非常危險的。第二個解決方案就是使用Application Context。這個context會伴隨你的應用而存在,並且不依賴Activity的的生命周期。如果你計劃保持一個需要context的長生命周期的對象,請記得考慮Application對象。你可以非常方便的通過調用Context.getApplicationContext() 或者 Activity.getApplication()獲取它。

總之,為了避免涉及到context的內存洩露,請記住如下幾點:

1.不要對一個Activity Context保持長生命周期的引用(一個對Activity的引用應該與Activity自身的生命周期相同)
2.嘗試使用應用上下文(context-application)代替活動上下文(context-activity)
3.如果你不能控制它們的生命周期,在活動(Activity)中避免使用不是靜態的內部類,使用靜態類並且使用弱引用到活動(Activity)的內部。對於這個問題的解決方法是使用靜態的內部類與一個弱引用(WeakReference)的外部類。就像ViewRoot和它的W內部類那麼實現的。
4.垃圾回收器對於內存洩露來說並不是百分百保險的。

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved