天天看點

android記憶體優化

android記憶體優化

@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。現在想象一下,你寫了一個應用,有一個非常大的位圖,并且你并不想在每次旋轉時都重新載入。保留它并且每次旋轉不重新加載的最簡單的辦法就是把它儲存在一個靜态字段上:

android記憶體優化

private static drawable sbackground;  

  if (sbackground == null) {  

    sbackground = getdrawable(r.drawable.large_bitmap);  

  }  

  label.setbackgrounddrawable(sbackground);  

    這段代碼非常快,同時也錯的夠離譜。它洩露了當第一次螢幕角度改變時建立的第一個活動(activity)。當一個drawable被附加到一個view,這個view被設定為drawable的一個回調。在上面的代碼片斷中,這意味着這個drawable對textview有一個引用,同時這個textview對activity(context對象)保持着引用,同時這個activity對很多對象又有引用(這個多少還要看你的代碼了)。

    有兩種簡單的方法可以避免與context相關的記憶體洩露。最明顯的一個就是避免在context的自身的範圍外使用它。上面的例子展示了在類内部的一個靜态的引用和它們對外部類的間接引用是非常危險的。第二個解決方案就是使用application context。這個context會伴随你的應用而存在,并且不依賴activity的的生命周期。如果你計劃保持一個需要context的長生命周期的對象,請記得考慮application對象。你可以非常友善的通過調用context.getapplicationcontext()

或者 activity.getapplication()擷取它。

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

不要對一個activity context保持長生命周期的引用(一個對activity的引用應該與activity自身的生命周期相同)

嘗試使用應用上下文(context-application)代替活動上下文(context-activity)

如果你不能控制它們的生命周期,在活動(activity)中避免使用不是靜态的内部類,使用靜态類并且使用弱引用到活動(activity)的内部。對于這個問題的解決方法是使用靜态的内部類與一個弱引用(weakreference)的外部類。就像viewroot和它的w内部類那麼實作的。

垃圾回收器對于記憶體洩露來說并不是百分百保險的。

繼續閱讀