LeakCanary 傻瓜式的內存泄露檢測工具

在開發Android應用的過程當中若是須要處理圖片或者大量數據的時候,就有可能會遇到OOMjava.lang.OutOfMemoryError),通常出現最多的是在建立Bitmap上,也有多是在內存中處理了大量的數據上。出現OOM應用會直接崩潰,即便沒有出現OOM,內存使用過大的時候應用也會出現卡頓。因此內存的優化在開發Android應用時是一個比較重要的任務。
通常會針對Bitamp的內存優化有下面幾種方式:javascript

1. 增長進程的內存
2. 使用Bitmap.Config.ALPHA_8(圖片失真)
3. 顯示的調用System.gc()
4. catch Exception
5. 調用bitmap.recycle()
6. 縮小bitmap的大小(若是是讀取的原圖是一個大圖應該先採用這種方式,Bitmap若是是恰好適配屏幕的就不須要縮小了)
7. 使用弱引用和軟引用(google已經不建議使用了,Android的GC效率很是高,只要保證對象沒有被引用便可)複製代碼

可是咱們忽略掉一個問題就是什麼形成了OOM
通常來講發生OOM崩潰的地方不必定是內存泄露的地方,崩潰的緣由有多是Activity形成的內存泄露,也多是操做數據庫形成的內存泄露,當內存已經很是接近峯值的時候,這個時候恰巧要建立一個Bitmap對象就會發生OOM(Bitmap對象佔用的內存比較大)。
是什麼緣由形成了內存泄露呢?java

內存泄露

咱們知道Android中每一個對象都有本身的生命週期,好比Activity的生命週期最後會調用onDestroy方法作銷燬處理,但若是使用Activity中調用了相似於Toast這種對象,就會把這個Activity的引用傳給了Toast,而Toast的生命週期不會隨着Activity的銷燬而銷燬,這樣就形成了Activity的內存泄露,它會被Toast對象引用,沒法被銷燬。
常見的內存泄露造成的緣由:android

  • Toast持有Activity的引用
  • 數據庫遊標Cursor沒有關閉
  • Adapter沒有複用convertView
  • 對象被生命週期更長的對象引用,Activity被靜態集合引用
  • ....

那如何知道應用的內存有沒有出現泄露呢?git

監控內存的方式

Heap Dump:常見的內存監控方式是Heap DumpHeap Dump是一種在Java中比較經常使用的檢測內存的方式:github

簡單來講就是咱們在一個初始狀態A, 在這個時候Dump一次內存,在作了一些操做以後回到狀態A,再Dump一次內存。
對兩次Dunp的內存數據(hprof)使用分析工具作分析(MAT),根據分析的結果就能知道是否存在內存泄露,這種方式比較複雜和繁瑣並非特別易用。算法

Moitors:這是Android SDK自帶的內存監控工具,Monitors能檢測到內存的變化,好比內存是增長仍是減小。
打開一個Activity會致使內存增長,關閉一個Activity會致使內存減小,反覆的作這樣的操做,若是每次打開一個Activity再關閉以後增長的內存不會減小就說明這個Activity有可能有內存泄露,再借助log輔助進行檢測,就能夠發現內存泄露的問題,
這種方式的缺點是並非特別的準確,由於內存的釋放和對象的生命週期有關也和GC的調度有關。
另外一種方式就是LeakCanary,LeakCanary是一個簡單的,方便的內存檢測工具,能夠輕易的發現內存問題,還會生成更加簡單清晰的報告。數據庫

LeakCanary

LeakCanary是一個開源的檢測內存泄露的java庫。項目地址:github.com/square/leak…
LeakCanary實際上就是在本機上自動作了Heap dump,對生成的hprof文件進行分析,展現分析的結果。和手工分析Heap Dump的方式獲得的結果是同樣的。只不過這部分的工做徹底自動化完成了。
下面是一個LeakCanary的結果截圖:緩存

LeakCanary

從上圖能夠看到,LeakCanary能清晰簡單的展現出那裏有內存泄露的問題。那LeakCanary如何使用呢?ide

集成LeakCanary

build.gradle添加依賴:工具

dependencies {
   debugCompile 'com.squareup.leakcanary:leakcanary-android:1.3.1'
   releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.3.1'
   testCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.3.1'
 }複製代碼

使用LeakCanary對應用進行檢測它會影響程序的性能,尤爲是在作Heap dump分析操做時,所以須要在依賴裏面指定對應的版本,debug的時候才進行分析,release的時候不能進行分析。
debugCompile可使用檢測版本:

com.squareup.leakcanary:leakcanary-android

releaseCompile使用no-op模式,即No Operation Performed就是不會把對應的類庫編譯,指定類庫爲無用的指令:

com.squareup.leakcanary:leakcanary-android-no-op

這樣就能夠指定LeakCanary爲無用指令,不會在release的時候進行編譯。
Application中加入分析Activity的代碼:

public class ExampleApplication extends Application {

  @Override public void onCreate() {
    super.onCreate();
    LeakCanary.install(this);
  }
}複製代碼

這樣就能夠檢測全部Activity的內存泄露了。LeakCanary內部實現使用了ActivityLifecycleCallbacks方法監聽全部Activity的生命週期。
除了Activity會發生內存泄露之外,其餘對象也有可能會出現內存泄露,若是對其餘對象進行檢測呢?

檢測其餘對象

LeakCanary中提供了RefWatcher類,能夠用來監控全部的對象。
首先實例化RefWatcher:

public static RefWatcher sRefWatcher=LeakCanary.install(mContext);複製代碼

對於監控的對象使用:

sRefWatcher.watch(this)複製代碼

通常咱們是在對象銷燬的時候對對象進行監控,好比內部實現的對於Activity的監控的原理以下:

private final ActivityLifecycleCallbacks lifecycleCallbacks = new ActivityLifecycleCallbacks() {
        public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
        }

        public void onActivityStarted(Activity activity) {
        }

        public void onActivityResumed(Activity activity) {
        }

        public void onActivityPaused(Activity activity) {
        }

        public void onActivityStopped(Activity activity) {
        }

        public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
        }

        public void onActivityDestroyed(Activity activity) {
            ActivityRefWatcher.this.onActivityDestroyed(activity);
        }
    };複製代碼

只是在onActivityDestroyed的時候纔對於activity進行監控便可。
檢測到了內存泄露,若是解決呢?

解決內存泄露

通常狀況內存泄露的緣由都是因爲引用的使用不當形成的,Android GC可以保證回收循環引用(若是一個循環引用沒有外部引用時就會被回收),且Android GC效率很高,固然GC的算法自己也在不停的改進。
通常狀況下只須要儘可能避免錯誤的引用方式帶來的內存泄露問題便可:

  • 生命週期長的對象引用生命週期短的對象,好比static的對象羣引用Activity
  • 使用Application的Context對象,而不是Activity的Context
  • 避免非靜態類的內部類對於類的隱式引用,使用靜態的內部類
  • 使用Android的緩存機制,好比ListView的複用機制
  • 手動關閉資源,好比Curous的關閉
  • registerReceiver和unRegisterReceiver成對出現
相關文章
相關標籤/搜索