Android內存優化(六)LeakCanary使用詳解

相關文章
Android性能優化系列
Java虛擬機系列html

1.概述

若是使用MAT來分析內存問題,會有一些難度,而且效率也不是很高,對於一個內存泄漏問題,可能要進行屢次排查和對比。
爲了可以簡單迅速的發現內存泄漏,Square公司基於MAT開源了LeakCanary
java

2.使用LeakCanary

首先配置build.gradle:android

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

接下來在Application加入以下代碼。git

public class LeakApplication extends Application {
    @Override public void onCreate() {
    super.onCreate();
    if (LeakCanary.isInAnalyzerProcess(this)) {//1
      // This process is dedicated to LeakCanary for heap analysis.
      // You should not init your app in this process.
      return;
    }
    LeakCanary.install(this);
  }
}複製代碼

註釋1處的代碼用來進行過濾操做,若是當前的進程是用來給LeakCanary 進行堆分析的則return,不然會執行LeakCanary的install方法。這樣咱們就可使用LeakCanary了,若是檢測到某個Activity 有內存泄露,LeakCanary 就會給出提示。github

3.LeakCanary應用舉例

第二節的例子代碼只可以檢測Activity的內存泄漏,固然還存在其餘類的內存泄漏,這時咱們就須要使用RefWatcher來進行監控。改寫Application,以下所示。性能優化

public class LeakApplication extends Application {
    private RefWatcher refWatcher;
    @Override
    public void onCreate() {
        super.onCreate();
        refWatcher= setupLeakCanary();
    }
    private RefWatcher setupLeakCanary() {
        if (LeakCanary.isInAnalyzerProcess(this)) {
            return RefWatcher.DISABLED;
        }
        return LeakCanary.install(this);
    }

    public static RefWatcher getRefWatcher(Context context) {
        LeakApplication leakApplication = (LeakApplication) context.getApplicationContext();
        return leakApplication.refWatcher;
    }
}複製代碼

install方法會返回RefWatcher用來監控對象,LeakApplication中還要提供getRefWatcher靜態方法來返回全局RefWatcher。
最後爲了舉例,咱們在一段存在內存泄漏的代碼中引入LeakCanary監控,以下所示。微信

public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        LeakThread leakThread = new LeakThread();
        leakThread.start();
    }
    class LeakThread extends Thread {
        @Override
        public void run() {
            try {
                Thread.sleep(6 * 60 * 1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    @Override
    protected void onDestroy() {
        super.onDestroy();
        RefWatcher refWatcher = LeakApplication.getRefWatcher(this);//1
        refWatcher.watch(this);
    }
}複製代碼

MainActivity存在內存泄漏,緣由就是非靜態內部類LeakThread持有外部類MainActivity的引用,LeakThread中作了耗時操做,致使MainActivity沒法被釋放。關於內存泄漏能夠查看Android內存優化(三)避免可控的內存泄漏這篇文章。
在註釋1處獲得RefWatcher,並調用它的watch方法,watch方法的參數就是要監控的對象。固然,在這個例子中onDestroy方法是多餘的,由於LeakCanary在調用install方法時會啓動一個ActivityRefWatcher類,它用於自動監控Activity執行onDestroy方法以後是否發生內存泄露。這裏只是爲了方便舉例,若是想要監控Fragment,在Fragment中添加如上的onDestroy方法是有用的。
運行程序,這時會在界面生成一個名爲Leaks的應用圖標。接下來不斷的切換橫豎屏,這時會閃出一個提示框,提示內容爲:「Dumping memory app will freeze.Brrrr.」。再稍等片刻,內存泄漏信息就會經過Notification展現出來,好比三星S8的通知欄以下所示。
app

Notification中提示了MainActivity發生了內存泄漏, 泄漏的內存爲787B。點擊Notification就能夠進入內存泄漏詳細頁,除此以外也能夠經過Leaks應用的列表界面進入,列表界面以下圖所示。ide

內存泄漏詳細頁以下圖所示。
工具

點擊加號就能夠查看具體類所在的包名稱。整個詳情就是一個引用鏈:MainActiviy的內部類LeakThread引用了LeakThread的this$0this$0的含義就是內部類自動保留的一個指向所在外部類的引用,而這個外部類就是詳情最後一行所給出的MainActiviy的實例,這將會致使MainActivity沒法被GC,從而產生內存泄漏。

除此以外,咱們還能夠將 heap dump(hprof文件)和info信息分享出去,以下圖所示。

device-2017-09-02-181759_副本.png
device-2017-09-02-181759_副本.png

須要注意的是分享出去的hprof文件並非標準的hprof文件,還須要將它轉換爲標準的hprof文件,這樣纔會被MAT識別從而進行分析,關於MAT能夠查看Android內存優化(五)詳解內存分析工具MAT這篇文章。

解決方法就是將LeakThread改成靜態內部類。

public class MainActivity extends AppCompatActivity {
  ...
    static class LeakThread extends Thread {
        @Override
        public void run() {
            try {
                Thread.sleep(6 * 60 * 1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
...
}複製代碼

再次運行程序LeakThread就不會給出內存泄漏的提示了。

參考資料
《高性能Android應用開發》
使用LeakCanary檢測安卓中的內存泄漏(實戰)
github.com/square/leak…
LeakCanary 中文使用說明
Android 源碼系列之<十三>從源碼的角度深刻理解LeakCanary的內存泄露檢測機制(中)


歡迎關注個人微信公衆號,第一時間得到博客更新提醒,以及更多成體系的Android相關原創技術乾貨。
掃一掃下方二維碼或者長按識別二維碼,便可關注。

相關文章
相關標籤/搜索