LeakCanary是Square开源的Java与Android内存泄漏检测工具:https://github.com/square/leakcanary,当前最新版本:1.6.2。
一、在Android项目中集成与使用
在Android项目中集成与使用LeakCanary相当简单:1. 添加项目依赖
在构建脚本
build.gradle
中添加对LeakCanary库的依赖:
dependencies {
debugImplementation 'com.squareup.leakcanary:leakcanary-android:1.6.2'
releaseImplementation 'com.squareup.leakcanary:leakcanary-android-no-op:1.6.2'
testImplementation 'com.squareup.leakcanary:leakcanary-android-no-op:1.6.2'
}
可以看到,release及test使用的是no-op的版本,no-op版本中接口都是空实现,因此不影响发布版本的业务逻辑,也不会影响效率。2. 初始化LeakCanary
在Application中对LeakCanary工具进行初始化:
public class ExampleApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
if (LeakCanary.isInAnalyzerProcess(this)) {
// LeakCanary会创建单独的进程用于内存堆分析,这里不应该调用我们的初始化代码,直接返回即可
return;
}
LeakCanary.install(this);
// 程序的初始化代码
}
}
LeakCanary初始化时会注册系统Activity生命周期监听器,监听所有Activity的onDestroy方法调用,以此分析Activity的内存泄漏:
@TargetApi(14)
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();
}
}
public ActivityRefWatcher(Application application, RefWatcher refWatcher) {
this.application = (Application)Preconditions.checkNotNull(application, "application");
this.refWatcher = (RefWatcher)Preconditions.checkNotNull(refWatcher, "refWatcher");
}
void onActivityDestroyed(Activity activity) {
this.refWatcher.watch(activity);
}
public void watchActivities() {
this.stopWatchingActivities();
this.application.registerActivityLifecycleCallbacks(this.lifecycleCallbacks);
}
public void stopWatchingActivities() {
this.application.unregisterActivityLifecycleCallbacks(this.lifecycleCallbacks);
}
}
3. 监听其他对象
Android中最常见的内存泄漏就是Context的内存泄漏,包括Activity、BroadcastReceiver、Service等,还有常见的Fragment等的泄漏。LeakCanary初始化时已经添加了所有Activity的监听,不需要我们再额外处理。下面看看其他对象的监听
分析Fragment内存泄漏分析,首先需要获取一个RefWatcher实例的引用:
public class ExampleApplication extends Application {
private static RefWatcher sRefWatcher;
@Override
public void onCreate() {
super.onCreate();
if (LeakCanary.isInAnalyzerProcess(this)) {
// LeakCanary会创建单独的进程用于内存堆分析,这里不应该调用我们的初始化代码,直接返回即可
return;
}
sRefWatcher = LeakCanary.install(this);
// 程序的初始化代码
}
public static void watch(final Object watchReference) {
if(null != sRefWatcher) {
sRefWatcher.watch(watchReference);
}
}
}
在Fragment的onDestroy中监听:
public class BaseFragment extends Fragment {
@Override
public void onDestroy() {
super.onDestroy();
ExampleApplication.watch(this);
}
}
其他对象的监听类似,在将要释放对象时,增加对象的监听:
ExampleApplication.watch(obj);
4. 收集内存泄漏及分析:
项目中集成LeakCanary后,运行debug程序,一段时间后退出程序。桌面上LeakCanary额外创建了一个名为"Leaks"的快捷方式,打开快捷方式可以看到一条条的内存泄漏日志,如下图示例:点击内存泄漏日志,可以查看内存泄漏详情,以此修复程序内存泄漏。
二、工作原理
- LeakCanary中调用
RefWatcher.watch()
方法会创建一个KeyedWeakReference的弱引用来监控对象 - 一段时间后,背景线程会检测这个引用对象是否被回收,如果没有被回收,则主动触发一次
GC
进行垃圾回收 - 如果这个引用对象仍然没有被回收,则dump堆内存到一个
.hprof
文件中存储到文件系统 - LeakCanary会在一个单独的进程中启动
HeapAnalyzerService
,这个Service
会调用HeapAnalyzer
分析内存dump,而HeapAnalyzer
使用得是另外一个Square开源工具HAHA来分析Android堆内存的dump文件 HeapAnalyzer
根据唯一key来找到堆内存中KeyedWeakReference
对象并定位内存泄漏对象的引用HeapAnalyzer
三. 更多
https://github.com/square/leakcanaryhttps://github.com/square/leakcanary/wiki/FAQ
https://github.com/square/leakcanary/wiki/Customizing-LeakCanary
http://droidyue.com/blog/2016/03/28/android-leakcanary/index.html
没有评论:
发表评论