Bootstrap

(原创)内存泄漏分析解决方案(二):LeakCanary介绍和使用

前言

上一篇我们讲了内存泄漏的情况和解决方案

(原创)内存泄漏分析解决方案(一):内存泄漏的几种情况解决方式

但是在实际开发中,我们是很难通过肉眼去直观定位内存泄漏问题的

这时候就需要用到一些工具

这次讲到的,就是一款名为LeakCanary的工具

什么是LeakCanary

LeakCanary是一个用来检测Android内存泄漏的框架,

作为一个实用工具,我们可以用它来定位和收集项目中存在的内存泄漏问题

LeakCanary更新到现在,目前的集成和使用已经比较简单了。

下面开始介绍它的使用方法。

LeakCanary使用

正式开始使用前,需要导入依赖,目前我使用的是2.6版本


dependencies {
  // debugImplementation because LeakCanary should only run in debug builds.
  debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.6'
}

老版本的LeakCanary还需要在application里面一顿配置

但是新版本已经不需要了,直接依赖就完成啦!

导入依赖完成后,运行我们的项目,然后查看log台如下
在这里插入图片描述
1代表我们要过滤的是LeakCanary的日志信息

2代表我们要查找的标记字段Leaking

3代表LeakCanary现在开始运行了

运行开始后,我们去使用我们的项目

可以随意进入一些页面再退出

或者如果想专门查看某一个Activity是否有泄漏

就多次进入这个Activity再退出

过一会后,会弹出一个这样的toast

另外,如果没有主动弹出

我们也可以通过在我们模拟器桌面上多出的一个Leaks入口

进去入口后点击这个Dump Heap Now按钮,也可以立马执行内存分析

这时候,我们去查看我们的日志台

主要关注Leaking字段

在这里插入图片描述
Leaking有三个状态,代表不同的含义

Leaking:YES:发生了内存泄漏

Leaking:NO:未发生内存泄漏

Leaking:UNKNOW:未知,可能发生泄漏

这里我们的截图显示

在MainActivity2发生了一处内存泄漏

具体位置是在MyHandler

通过这个日志台,我们就可以清楚的知道内存泄漏的情况和具体未知了

另外,进入我们模拟器的桌面上的Leaks入口也可以看到这些日志信息

LeakCanary实战小例子

接下来,我们自己来写一个小例子,然后看LeakCanary能否检测到我们的内存泄漏

我们用java写一个单例模式

public class SingerDemo {
 
    private Context context;
    private static SingerDemo instance;
 
    private SingerDemo(Context context) {
        this.context = context;
    }
 
    public static SingerDemo getInstance(Context context) {
        if (instance == null) {
            instance = new SingerDemo(context);
        }
        return instance;
    }
}

然后我们把MainActivity2作为参数传入进去


override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main2)
tv=findViewById(R.id.textView)
//传入activity对象
SingerDemo.getInstance(this)
}

因为单例持有了MainActivity2的引用,所以我们在MainActivity里多次进入MainActivity2然后退出
MainActivity2就会在内存中存在多个对象无法释放,从而发生了内存泄漏
我们用LeakCanary调试,log台得到如下结果

====================================
HEAP ANALYSIS RESULT
====================================
1 APPLICATION LEAKS
 
References underlined with "~~~" are likely causes.
Learn more at https://squ.re/leaks.
 
80373 bytes retained by leaking objects
Signature: 5021752607a5418ce492c6d6258a4a05358ce1
┬───
│ GC Root: Local variable in native code
│
├─ android.os.HandlerThread instance
│ Leaking: NO (PathClassLoader↓ is not leaking)
│ Thread name: 'LeakCanary-Heap-Dump'
│ ↓ Thread.contextClassLoader
├─ dalvik.system.PathClassLoader instance
│ Leaking: NO (SingerDemo↓ is not leaking and A ClassLoader is never leaking)
│ ↓ ClassLoader.runtimeInternalObjects
├─ java.lang.Object[] array
│ Leaking: NO (SingerDemo↓ is not leaking)
│ ↓ Object[].[667]
├─ com.example.memorytest.util.SingerDemo class
│ Leaking: NO (a class is never leaking)
│ ↓ static SingerDemo.instance
│ ~~~~~~~~
├─ com.example.memorytest.util.SingerDemo instance
│ Leaking: UNKNOWN
│ Retaining 80.4 kB in 1278 objects
│ context instance of com.example.memorytest.MainActivity2 with mDestroyed = true
│ ↓ SingerDemo.context
│ ~~~~~~~
╰→ com.example.memorytest.MainActivity2 instance
​ Leaking: YES (ObjectWatcher was watching this because com.example.memorytest.MainActivity2 received
​ Activity#onDestroy() callback and Activity#mDestroyed is true)
​ Retaining 80.4 kB in 1277 objects
​ key = 37b6654c-f318-41c1-b29f-63979a1fcc85
​ watchDurationMillis = 216967
​ retainedDurationMillis = 211965
​ mApplication instance of android.app.Application
​ mBase instance of android.app.ContextImpl
====================================
0 LIBRARY LEAKS
 
A Library Leak is a leak caused by a known bug in 3rd party code that you do not have control over.
See https://square.github.io/leakcanary/fundamentals-how-leakcanary-works/#4-categorizing-leaks
====================================
0 UNREACHABLE OBJECTS

我们找到关键的Leaking:YES
得到如下信息

在这里插入图片描述
果然定位到了由单例导致的内存泄漏
接下来我们只需要对我们的单例这样做修改


    private SingerDemo(Context context) {
//        this.context = context;
        this.context = context.getApplicationContext();
    }

再去查看内存检测结果
在这里插入图片描述
发现已经没有内存泄漏了
这样就解决了单例导致的内存泄漏问题

最后,关于LeakCanary的源码的解读和原理的分析
这里也有一篇博客作为参考,感兴趣的可以看下
【带着问题学】关于LeakCanary2.0你应该知道的知识点
LeakCanary介绍和使用就讲到这里了。

;