一言以蔽之:LeakCanary是一个 傻瓜化 并且可视化的内存泄露分析工具
因为它简单,易于发现问题,人人可参与。
尽量在app下的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中加入类似如下的代码
public class ExampleApplication extends Application { @Override public void onCreate() { super.onCreate(); LeakCanary.install(this); } }
到这里你就可以检测到Activity的内容泄露了。其实现原理是设置Application的ActivityLifecycleCallbacks方法监控所有Activity的生命周期回调。内部实现代码为
public final class ActivityRefWatcher { 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); } }; private final Application application; private final RefWatcher refWatcher; public static void installOnIcsPlus(Application application, RefWatcher refWatcher) { if(VERSION.SDK_INT >= 14) { ActivityRefWatcher activityRefWatcher = new ActivityRefWatcher(application, refWatcher); activityRefWatcher.watchActivities(); } } .... }
首先我们需要获得一个RefWatcher,用来后续监控可能发生泄漏的对象
public class MyApplication extends Application { private static RefWatcher sRefWatcher; @Override public void onCreate() { super.onCreate(); sRefWatcher = LeakCanary.install(this); } public static RefWatcher getRefWatcher() { return sRefWatcher; } }
监控某个可能存在内存泄露的对象
MyApplication.getRefWatcher().watch(sLeaky);
默认情况下,是对Activity进行了检测。另一个需要监控的重要对象就是Fragment实例。因为它和Activity实例一样可能持有大量的视图以及视图需要的资源(比如Bitmap)即在Fragment onDestroy方法中加入如下实现
public class MainFragment extends Fragment { @Override public void onDestroy() { super.onDestroy(); MyApplication.getRefWatcher().watch(this); } }
其他也可以监控的对象
首先,我们需要明确什么是内存泄露,简而言之,某个对象在该释放的时候由于被其他对象持有没有被释放,因而造成了内存泄露。
因此,我们监控也需要设置 在对象(很快)被释放的时候 ,如Activity和Fragment的onDestroy方法。
一个错误示例,比如监控一个Activity,放在onCreate就会大错特错了,那么你每次都会收到Activity的泄露通知。
常用的解决方法思路如下
有些特殊情况,我们需要忽略一些问题,这时候就需要添加例外规则。比如ExampleClass.exampleField会导致内存泄漏,我们想要忽略,如下操作即可。
// ExampleApplication is defined in "Customizing and using the no-op dependency" public class DebugExampleApplication extends ExampleApplication { protected RefWatcher installLeakCanary() { ExcludedRefs excludedRefs = AndroidExcludedRefs.createAppDefaults() .instanceField("com.example.ExampleClass", "exampleField") .build(); return LeakCanary.install(this, DisplayLeakService.class, excludedRefs); } }
LeakCanary实际上就是在本机上自动做了Heap dump,然后对生成的hprof文件分析,进行结果展示。和手工进行MAT分析步骤基本一致。
是的,这个问题确实值得关注,因为LeakCanary确实是影响程序运行的,尤其是heap dump操作,不过好在这件事Square已经考虑了,即在我们增加依赖时
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
其中releaseCompile和testCompile这两个的依赖明显不同于debugCompile的依赖。它们的依赖属于NOOP操作。
NOOP,即No Operation Performed,无操作指令。常用的编译器技术会检测无操作指令并出于优化的目的将无操作指令剔除。
因而,只要配置好releaseCompile和testCompile的依赖,就无需担心对外版本的性能问题了。