Android:內存控制及OOM處理

1. OOM(內存溢出)和Memory Leak(內存泄露)有什麼關係?

OOM多是由於Memory Leak,也多是你的應用自己就比較耗內存(好比圖片瀏覽型的)。因此,出現OOM不必定是Memory Leak。 html

一樣,Memory Leak也不必定就會致使OOM,若是泄露的速度很慢,可能還沒用完可用內存應用就被重啓了,那就不會OOM咯。固然了,有bug解決了最好。 java

2. 什麼是shallow heap與retained heap?

  • shallow heap:你自身佔了多少內存,好比你有一個int屬性,就佔4字節。不包括你引用的其餘對象。
  • retained heap:若是你被銷燬,總共會釋放多少內存。這些因你存在被佔據的空間就是retained heap。

3. 什麼是GC roots?

GC的時候,是從這些節點開始遍歷,不停的尋找其子節點直到結束。而後把不能遍歷到的節點釋放。這些遍歷的起點(注意,可不是一個哦)就叫作GC roots。 android

那,對於java來講,誰是GC roots?簡單點說(不是那麼準確)包括如下幾種: app

  • 棧上面的局部變量
  • 棧上面的函數參數變量
  • 全部由Bootstrap Loader加載的類變量
  • 另外,JNI相關的也會有
  • 更多詳細解釋請看這篇博客

4. 怎樣使用MAT定位內存泄露?

4.1 看Histogram(類統計圖) 異步

histogram未過濾

對於Android程序來講,內存泄露一般都會牽扯到activity。所以,dump以前,能夠多旋轉幾回屏幕並反覆的進出可能有問題的activity,讓問題儘量的凸現。
經過Histogram咱們能夠看每一個類有多少個實例,shallow和retained heap分別有多大。若是隻是看java的基礎類型和framework的類,沒有什麼意義,必定要過濾出本身的類型,以下圖 ide

Histogram 已過濾cn

發現LeakInnerClassActivity產生了9個實例,必定是被hold住了。 函數

4.2 看Dominator Tree spa

Dominator Tree

怎樣使用還沒弄清楚,感受和histogram比沒啥特點捏,嘿嘿 code

4.3 對比heap dumps,能夠更快的定位內存泄露的位置。操做步驟: orm

  • 打開一個HPROF文件,切換到histogram視圖
  • 在Navigation View中右鍵點擊histogram,選擇Add to compare basket
  • 打開另外一個HPROF文件,並重覆上一個步驟
  • 對比兩次heap dumps的內容,看下圖,LeakInnerClassActivity的實例又增長了一個。而我僅僅是又啓動了一次該Activity,因此問題顯而易見。

histogram compare

參考:Memory Analysis for Android Applications

5. 內部類怎樣使用纔會產生內存泄露,以及由此衍生的AsyncTask、Handler問題如何解決?

  • 若是非靜態內部類的方法中,有生命週期大於其所在類的,那就有問題了。好比:AsyncTask、Handler,這兩個類都是方便開發者執行異步任務的,可是,這兩個都跳出了Activity/Fragment的生命週期。
  • 爲何?由於非靜態內部類會自動持有一個所屬類的實例,若是所屬類的實例已經結束生命週期,但內部類的方法仍在執行,就會hold其主體。也就使主體不能被釋放,亦即內存泄露。
  • 靜態類呢?靜態類編譯後和非內部類是同樣的,有本身獨立的類名。不會悄悄引用所屬類的實例,因此就不容易泄露。

    

//首先,靜態類
static class IncomingHandler extends Handler {
    //其次,弱引用
    private final WeakReference<UDPListenerService> mService; 

    IncomingHandler(UDPListenerService service) {
        mService = new WeakReference<UDPListenerService>(service);
    }
    @Override
    public void handleMessage(Message msg) {
         UDPListenerService service = mService.get();
         if (service != null) {
              service.handleMessage(msg);
         }
    }
}

6. 圖片致使的OOM如何解決?

  • 加載時使用option,用多大,載入多大。
  • res目錄下的圖片也是同樣,及時清理過大的圖片資源。
  • 若是還有問題,就想辦法把不可見的資源釋放掉,好比,TabActivity中不可見的Tab,ViewPager中的Fragment。
  • 若是activity的圖片資源較多,須要考慮屏幕旋轉時,銷燬已有資源。請參考這篇文章

7. 須要context的時候用activity仍是application?

  • 看使用的週期是否在activity週期內,若是超出,必須用application;常見的情景包括:AsyncTask,Thread,第三方庫初始化等等。
  • 還有些情景,只能用activity:好比,對話框,各類View,須要startActivity的等。
  • 總之,儘量使用Application。參考stackoverflow

8. 何時須要手動將變量設置爲NULL?

  • 類變量,一旦用完,儘快釋放。由於類的存活時間最長,因此,佔用的資源越少越好;
  • 比較耗時且耗內存的方法內的局部變量,好比,圖片處理的方法,每一個bitmap對象用完就及時丟棄。儘量讓gc介入。
相關文章
相關標籤/搜索