前言
依稀记得有场面试问过这个问题。虽然已经忘记是哪场面试,这里还是做一个记录和学习。
我们都知道使用LeakCanary
这个第三方依赖主要是为了避免内存泄露问题。
当应用异常退出的时候,我们为了重现问题,通常需要去寻找特定的机型。但实际上并不怎么现实,且手段比较粗暴。
我们希望在发生内存泄露的时候,可以把内存 Dump
出来。然后就可以借助MAT
等工具来进行内存分析,确定哪里代码的引用不是必须的。
而LeakCanary
只需要集成进去,就可以检测内存泄露。
1. LeakCanary的使用案例
首先在gradle
文件中引入依赖:
debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.3'
然后写第二个启动的Activity
,在这个类中写一个会导致内存泄漏的BUG
代码,如下:
public class TestActivity extends AppCompatActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test);
InnerClass.getInstance(this);
}
// 静态单例内部类,来持有context,导致回退后不能被释放
static class InnerClass{
private static InnerClass mInnerClass;
private Context context; // 持有外部的context
private InnerClass(Context context){
this.context = context;
}
public static InnerClass getInstance(Context context){
if(mInnerClass == null){
mInnerClass = new InnerClass(context);
}
return mInnerClass;
}
}
}
然后可以在第一个Activity
中设置点击后启动TestActivity
,然后进入后就回退,返回到第一个Activity
中。首先使用AndroidStudio
自带的Profiler
可以进行内存分析,可以发现内存泄漏问题,如下:
但是此时的LeakCanary
还是没有提示,当多操作几轮发现最终LeakCanary
有了具体的提示,如下:
从上面可以看出泄漏位置。但个人感觉还是没有自带的Profiler
分析的快,但比较直观。
至于Profiler
工具怎么使用,在我的上篇博客:Android中的性能优化方法中有比较详细的说明,这里不再复述。
2. LeakCanary原理
可以看下LeakCanary官网的介绍。
发现官网中正好有解释:How LeakCanary works?
分为四步:
- Detecting retained objects. 使用钩子来关联
Android
的生命周期,检测在Activity
或者Fragment
被销毁的时候哪些对象应该被GC
。如果这些弱引用对象在5秒后没有被GC
,那么这些对象被认为是保留的。 - Dumping the heap. 当保留对象达到了阈值,
LeakCanary
将Java
堆信息(heap dump)转储到Android
文件系统的文件中,通常叫做.hprof
。 - Analyzing the heap. 对每一个保留对象,
LeakCanary
从找到它的引用路径,即泄漏追踪。 - Categorizing leaks.
Thanks