LeakCanary是andrid 檢測內存泄漏的工具,使用起來比MAT方便很多
下面介紹LeakCanary 的使用
下面是在在androidStudio 中使用
首先 在 build.gradle 中加入引用,不同的編譯使用不同的引用:
dependencies {
debugCompile 'com.squareup.leakcanary:leakcanary-android:1.3.1' // or 1.4-beta1
releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.3.1' // or 1.4-beta1
testCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.3.1' // or 1.4-beta1
}
在Application 中使用,用於檢測所有Activity的內存泄漏狀況,只需要在Application onCreate()
方法中添加LeakCanary.install(this);
一行代碼就ok了
public class MyApplication extends Application{
public static RefWatcher getRefWatcher(Context context) {
@Override
public void onCreate() {
super.onCreate();
LeakCanary.install(this);
}
}
還可以檢測那些本該被回收的對象,使用RefWatcher
RefWatcher 用於:
1. 檢測調用 Activity.onDestroy() 之後泄露的 activity
2. 檢測 Fragment
檢測調用 Activity.onDestroy() 之後泄露的 activity
LeakCanary.install() 會返回一個預定義的 RefWatcher,同時也會啓用一個 ActivityRefWatcher,用於自動監控調用 Activity.onDestroy() 之後泄露的 activity。
public class MyApplication extends Application{
public static RefWatcher getRefWatcher(Context context) {
MyApplication application = (MyApplication) context.getApplicationContext();
return application.refWatcher;
}
private RefWatcher refWatcher;
@Override
public void onCreate() {
super.onCreate();
refWatcher = LeakCanary.install(this);
}
}
使用 RefWatcher 監控 Fragment
因爲它和Activity實例一樣可能持有大量的視圖以及視圖需要的資源(比如Bitmap)即在Fragment onDestroy方法中加入如下實現,使用refWatcher.watch(Object o)
監控Fragmeng對象
public abstract class BaseFragment extends Fragment {
@Override public void onDestroy() {
super.onDestroy();
RefWatcher refWatcher = MyApplication.getRefWatcher(getActivity());
refWatcher.watch(this);
}
}
模擬內存泄漏
public class TestDataModel {
private static TestDataModel sInstance;
private TextView mRetainedTextView;
public static TestDataModel getInstance() {
if (sInstance == null) {
sInstance = new TestDataModel();
}
return sInstance;
}
public void setRetainedTextView(TextView textView) {
mRetainedTextView = textView;
}
}
然後在Activity 和 Fragment 中分別調用
TextView textview = (TextView)view.findViewById(R.id.textview); TestDataModel.getInstance().setRetainedTextView(textview);
然後就可以運行程序了,別忘了MyApplication 在清單文件中聲明
當檢測到內存泄漏後,在通知欄中會以通知的形式通知
點進去查看詳情
如圖:
可以詳細的看到哪個包中的哪個類哪個變量引起的內存泄漏,很直觀
如果想要監控某個可能存在內存泄漏的對象
MyApplication.getRefWatcher().watch(sLeaky);//sLeaky 爲要監控的對象
其他也可以監控的對象
BroadcastReceiver
Service
其他有生命週期的對象
直接間接持有大內存佔用的對象(即Retained Heap值比較大的對象)
SDK 導致的內存泄露
在檢測出內存泄漏中,我們甚至可以看到sdk的內存泄漏
隨着時間的推移,很多SDK 和廠商 ROM 中的內存泄露問題已經被儘快修復了。但是,當這樣的問題發生時,一般的開發者能做的事情很有限。
LeakCanary 有一個已知問題的忽略列表,AndroidExcludedRefs.java,如果你發現了一個新的問題,請提一個 issue 並附上 leak trace, reference key, 機器型號和 SDK 版本。如果可以附帶上 dump 文件的 鏈接那就再好不過了。
對於最新發布的 Android,這點尤其重要。你有機會在幫助在早期發現新的內存泄露,這對整個 Android 社區都有極大的益處。
如何不影響對外版APK
可以看出我們在引入依賴時,都已經區分開了
debugCompile 'com.squareup.leakcanary:leakcanary-android:1.3.1' // or 1.4-beta1
releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.3.1' // or 1.4-beta1
testCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.3.1' // or 1.4-beta1
debugCompile、releaseCompile、testCompile 提供了三種不同的模式
其中releaseCompile和testCompile這兩個的依賴明顯不同於debugCompile的依賴。它們的依賴屬於NOOP操作。
NOOP,即No Operation Performed,無操作指令。常用的編譯器技術會檢測無操作指令並出於優化的目的將無操作指令剔除。
因而,只要配置好releaseCompile和testCompile的依賴,就無需擔心對外版本的性能問題了