關於Android內存泄漏的種種總結第二彈

銜接上篇:
新年事後獻上關於Android內存泄漏的種種總結
順手留下GitHub連接,須要獲取相關面試等內容的能夠本身去找
https://github.com/xiangjiana/Android-MS
(VX:mm14525201314)git

在Android應用的開發中,爲了防止內存溢出,在處理一些佔用內存大並且聲明周 期較長的對象時候,能夠儘可能應用軟引用和弱引用技術。github

軟/弱引用能夠和一個引用隊列(ReferenceQueue)聯合使用,若是軟引用所引用 的對象被垃圾回收器回收,Java虛擬機就會把這個軟引用加入到與之關聯的引用隊 列中。利用這個隊列能夠得知被回收的軟/弱引用的對象列表,從而爲緩衝器清除已 失效的軟/弱引用。 面試

假設咱們的應用會用到大量的默認圖片,好比應用中有默認的頭像,默認遊戲圖標 等等,這些圖片不少地方會用到。若是每次都去讀取圖片,因爲讀取文件須要硬件 操做,速度較慢,會致使性能較低。因此咱們考慮將圖片緩存起來,須要的時候直 接從內存中讀取。可是,因爲圖片佔用內存空間比較大,緩存不少圖片須要不少的 內存,就可能比較容易發生OutOfMemory異常。這時,咱們能夠考慮使用軟/弱引 用技術來避免這個問題發生。數組

如下就是高速緩衝器的雛形: 首先定義一個HashMap,保存軟引用對象。緩存

private Map <String, SoftReference<Bitmap>> imageCache = new Has 
  hMap <String, SoftReference<Bitmap>> ();

再來定義一個方法,保存Bitmap的軟引用到HashMap
關於Android內存泄漏的種種總結第二彈
使用軟引用之後,在OutOfMemory異常發生以前,這些緩存的圖片資源的內存空間 能夠被釋放掉的,從而避免內存達到上限,避免Crash發生。 若是隻是想避免OutOfMemory異常的發生,則可使用軟引用。架構

若是對於應用的性 能更在乎,想盡快回收一些佔用內存比較大的對象,則可使用弱引用。 app

另外能夠根據對象是否常用來判斷選擇軟引用仍是弱引用。若是該對象可能會 常用的,就儘可能用軟引用。若是該對象不被使用的可能性更大些,就能夠用弱 引用ide

ok,繼續回到主題。前面所說的,建立一個靜態Handler內部類,而後對 Handler 持有的對象使用弱引用,這樣在回收時也能夠回收 Handler 持有的對象,可是這樣 作雖然避免了 Activity 泄漏,不過 Looper 線程的消息隊列中仍是可能會有待處理的 消息,因此咱們在 Activity 的 Destroy 時或者 Stop 時應該移除消息隊列 MessageQueue中的消息。 oop

下面幾個方法均可以移除 Message:性能

public final void removeCallbacks(Runnable r); 
  public final void removeCallbacks(Runnable r, Object token); 
  public final void removeCallbacksAndMessages(Object token); 
  public final void removeMessages(int what); 
  public final void removeMessages(int what, Object object);
  • 儘可能避免使用 static 成員變量
    若是成員變量被聲明爲 static,那咱們都知道其生命週期將與整個app進程生命 週期同樣。

    這會致使一系列問題,若是你的app進程設計上是長駐內存的,那即便app切到 後臺,這部份內存也不會被釋放。按照如今手機app內存管理機制,佔內存較 大的後臺進程將優先回收,由於若是此app作過進程互保保活,那會形成app在 後臺頻繁重啓。當手機安裝了你參與開發的app之後一晚上時間手機被消耗空了 電量、流量,你的app不得不被用戶卸載或者靜默。 這裏修復的方法是:

不要在類初始時初始化靜態成員。能夠考慮lazy初始化。 架構設計上要思考是否真 的有必要這樣作,儘可能避免。若是架構須要這麼設計,那麼此對象的生命週期你有 責任管理起來。

  • 避免 override finalize()
    一、finalize 方法被執行的時間不肯定,不能依賴與它來釋放緊缺的資源。時間 不肯定的緣由是:
  • 虛擬機調用GC的時間不肯定
  • Finalize daemon線程被調度到的時間不肯定

二、finalize 方法只會被執行一次,即便對象被複活,若是已經執行過了 finalize 方法,再次被 GC 時也不會再執行了,緣由是:
含有 finalize 方法的 object 是在 new 的時候由虛擬機生成了一個 finalize reference 在來引用到該Object的,而在 finalize 方法執行的時候,該 object 所 對應的 finalize Reference 會被釋放掉,即便在這個時候把該 object 復活(即用 強引用引用住該 object ),再第二次被 GC 的時候因爲沒有了 finalize reference 與之對應,因此 finalize 方法不會再執行。

三、含有Finalize方法的object須要至少通過兩輪GC纔有可能被釋放。

  • 資源未關閉形成的內存泄漏
    對於使用了BraodcastReceiverContentObserver,File,遊標 Cursor, Stream,Bitmap等資源的使用,應該在Activity銷燬時及時關閉或者註銷,否 則這些資源將不會被回收,形成內存泄漏。
  • 一些不良代碼形成的內存壓力
    有些代碼並不形成內存泄露,可是它們,或是對沒使用的內存沒進行有效及時 的釋放,或是沒有有效的利用已有的對象而是頻繁的申請新內存。

好比:
構造 Adapter 時,沒有使用緩存的 convertView ,每次都在建立新的 converView。這裏推薦使用 ViewHolder

總結:

  • 對 Activity 等組件的引用應該控制在 Activity 的生命週期以內; 若是不能就考 慮使用 getApplicationContext 或者 getApplication,以免 Activity 被外部長 生命週期的對象引用而泄露。
  • 儘可能不要在靜態變量或者靜態內部類中使用非靜態外部成員變量(包括context ),即便要使用,也要考慮適時把外部成員變量置空;也能夠在內部類中使用弱 引用來引用外部類的變量。
  • 對於生命週期比Activity長的內部類對象,而且內部類中使用了外部類的成員變 量,能夠這樣作避免內存泄漏:
    • 將內部類改成靜態內部類
    • 靜態內部類中使用弱引用來引用外部類的成員變量
  • Handler 的持有的引用對象最好使用弱引用,資源釋放時也能夠清空 Handler 裏面的消息。好比在 Activity onStop 或者 onDestroy 的時候,取消掉該 Handler對象的 MessageRunnable.
  • 在 Java 的實現過程當中,也要考慮其對象釋放,最好的方法是在不使用某對象 時,顯式地將此對象賦值爲 null,好比使用完Bitmap 後先調用 recycle(),再賦 爲null,清空對圖片等資源有直接引用或者間接引用的數組(使用 array.clear() ; array = null)等,最好遵循誰建立誰釋放的原則。
  • 正確關閉資源,對於使用了BraodcastReceiverContentObserver,File,遊 標 Cursor,Stream,Bitmap等資源的使用,應該在Activity銷燬時及時關閉或 者註銷。
  • 保持對對象生命週期的敏感,特別注意單例、靜態對象、全局性集合等的生命 週期。

刪減了一部分,見諒^_^
順手留下GitHub連接,須要獲取相關面試等內容的能夠本身去找
https://github.com/xiangjiana/Android-MS
(VX:mm14525201314)
關於Android內存泄漏的種種總結第二彈

相關文章
相關標籤/搜索