LeakCanary提供了一种很方便的方式,让我们在开发阶段测试内存泄露,我们不需要自己根据内存块来分析内存泄露的原因,我们只需要在项目中集成他,然后他就会帮我们检测内存泄露,并给出内存泄露的引用链
集成
- 在gradle中添加依赖,这种不区分debug和release
implementation ‘com.squareup.leakcanary:leakcanary-android:1.5.1’
- 重写Application
public class App extends Application {
private RefWatcher mRefWatcher;
@Override
public void onCreate() {
super.onCreate();
if (LeakCanary.isInAnalyzerProcess(this)) {
// This process is dedicated to LeakCanary for heap analysis.
// You should not init your app in this process.
return;
}
mRefWatcher = LeakCanary.install(this);
}
public static RefWatcher getRefWatcher(Context context) {
App application = (App) context.getApplicationContext();
return application.mRefWatcher;
}
}
- 比如我们在Activity中制造Handler发延迟消息的内存泄露
public class ActivityOne extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_one);
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
}
}, 100000);
}
@Override
protected void onDestroy() {
super.onDestroy();
}
}
- 然后我们打开这个activity然后再关闭,桌面就会出现一个leaks的图标,然后我们打开它
这就是基本使用,其实这种形式只能监视Activity的内存泄露,至于为什么只能监视Activity的内存泄露我们下面再分析,如果想要监视其他的内存泄露怎么办,比如要监视Fragment的内存泄露,可以这样写,主动监视想要监视的对象
public abstract class BaseFragment extends Fragment {
@Override public void onDestroy() {
super.onDestroy();
RefWatcher refWatcher = App.getRefWatcher(getActivity());
refWatcher.watch(this);
}
}
原理概述
通过监听Activity的onDestory,手动调用GC,然后通过ReferenceQueue+WeakReference,来判断Activity对象是否被回收,然后结合dump Heap的hpof文件,通过Haha开源库分析泄露的位置
主要的知识点
注册Activity的生命周期的监听器
通过Application.registerActivityLifecycleCallbacks()
方法注册Activity的生命周期的监听器,每一个Actvity的生命周期都会回调到这个ActivityLifecycleCallbacks上,如果一个Activity走到了onDestory,那么就意味着他就不再存在,然后检测这个Activity是否是真的被销毁
通过ReferenceQueue+WeakReference,来判断对象是否被回收
WeakReference创建时,可以传入一个ReferenceQueue对象,假如WeakReference中引用对象被回收,那么就会把WeakReference对象添加到ReferenceQueue中,可以通过ReferenceQueue中是否为空来判断,被引用对象是否被回收
详细介绍推荐博客:www.jianshu.com/p/964fbc301…
MessageQueue中加入一个IdleHandler来得到主线程空闲回调
详细介绍请看Android Handler 源码解析
手动调用GC后还调用了System.runFinalization();
,这个是强制调用已失去引用对象的finalize方法
在可达性算法中,不可达对象,也不是非死不可,这时他们处于“缓刑”阶段,要宣告一个对象真正死亡需要至少俩个标记阶段, 如果发现对象没有引用链,则会进行第一次标记,并进行一次筛选,筛选的条件是此对象是否有必要进行finalize()方法,当对象没有覆盖finalize(),或者finalize()已经调用过,这俩种都视为“没有必要执