如何使用 AS 3.0 与 LeakCanary 快速分析内存泄漏

2,934 阅读5分钟

内存泄漏指的是进程中某些对象(垃圾对象)已经没有使用价值了,但是它们却可以直接或间接地引用到 gc roots 导致无法被 GC 回收。无用的对象占据着内存空间,使得实际可使用内存变小,形象地说法就是内存泄漏了。

说到内存泄露,就不得不提到内存溢出,这两个比较容易混淆的概念。

内存泄露是指你的应用使用资源之后没有及时释放,导致应用内存中持有了不需要的资源,这是一种状态描述。

内存溢出是指你的应用的内存已经不能满足正常使用了,堆栈已经达到系统设置的最大值,进而导致崩溃,这事一种结果描述。

而且通常都是由于内存泄露导致堆栈内存不断增大,从而引发内存溢出。

‍Android Profiler

在 Android Studio 3.0 中推出了新的 Android Profiler ,取代了之前的 Android Monitor,帮助我们可以更好的分析 CPU、Memory、Network 的使用情况。

第一步我们就使用 Android Profiler 来分析内存泄漏的问题,先看一个简单的内存泄漏的例子。

很明显图中的 TestLeak 是一个单例类,我们在 setRetainedTextView 中传入了一个 TextView,并把它赋值给 mRetainedTextView。单例模式保证一个类仅有一个实例,这个类还必须提供一个访问该类的全局访问点。同时单例的生命周期是与 Application 的生命周期相等的,也就意味着,当你使用一个单例的时候,只有 Application 被销毁的时候它才会被一起销毁。如果我们以下图中的方式在 Activity 中使用 TestLeak 就会产生内存泄漏。

由于 TestLeak 在内存中是一直存在的,所以它会一直持有我们传入的 TextView,导致我们的在退出 MemoryActivity 时,MemoryActivity 也不会被回收,从而引发了内存泄漏。

如何使用 Android Profiler 来分析内存泄漏?

运行我们的项目,然后打开 Android Profiler,你会看到上图中的界面,三个分类界面分别是 CPU、Memory、Network,点击 Memory,你会看到当前 app 中内存的分配情况。

假设你现在只意识到 app 有内存泄漏的情况,但并不清楚具体发生在那个类中,那么通过下面的方法,你可以精确的定位到发生内存泄漏的类中。

1. 首先我们对 app 进行正常的操作测试,就是重复打开关闭一些页面。

2. 回退到最外层的 Activity 中,理论上当前我们回退到这一页的时候,之前的 Activity 都应被销毁回收。

3. 点击上图中的 GC 图标,手动触发 GC 去回收资源,这是为了避免系统还没来及的回收,所以我们手动去 GC,确保剩下的都是不会被回收的资源。

4. 点击 GC 旁边的 Dump java heap,分析一下当前内存的堆栈情况。

5. 选择按包名查看。

这时你会看到各个包下的类,在内存中的使用情况,我以最开始的内存泄漏的例子,先向大家复述一下之前对 app 的操作。最外层的是 MainActivity,点击跳转到内存泄漏发生的 MemoryActivity 中,重复几次之前的操作,然后退回至 MainActivity,之后我们手动触发了 GC 来回收资源。

从上图中可以发现,即使我们回退到 MainActivity 中,当前内存中仍存在 MemoryActivity 的实例,这是因为我们所写的 TestLeak 持有了它的引用,导致它没有被回收,从而引发了内存泄漏。

正常情况下的内存应该这个样子的。

通过上面的方法,我们就可以快速的定位到发生内存泄漏的类中,如果定位到当前类但是里面有大量的逻辑代码,我想要更加精准的知道到底是由于什么导致内存泄漏该怎么做?这个时候,我们可以配合 LeakCanary 来帮助我们。

LeakCanary

LeakCanary 是 Square 开源的一个内存泄露自动探测神器。它是一个 Android 和 Java 的内存泄露检测库,可以大幅度帮助我们减少了开发中遇到的 OOM 问题。

如何使用?

1. 在项目的 Gradle 文件中依赖 LeakCanary

2. 在自定义的 Application 中初始化 LeakCanary

ok !就这么简单,之后只需要像上面的操作那样,正常对 app 进行测试就好了,因为我们已经通过 Android Profiler 知道具体内存泄漏是在哪个类产生的,所以我们可以着重对那个 Activity 进行测试。

当检测到内存泄漏时,LeakCanary 会在通知栏中弹出内存泄漏的警告,并且将内存的堆栈日志保存在 download 文件夹中。

从图中我们可以知道,在 MemoryActivity 中由于 TestLeak 持有 MemoryActivity 的引用导致无法被回收,从而引发了内存泄漏。

 

就是这么简单和方便,通过 Android Studio 3.0 和 LeakCanary 我们可以快速高效的分析出内存泄漏,赶快去实践一下吧!

探索有趣的新事物 

Android、Kotlin、设计、产品、思考、游戏。

长按关注

如果觉得有意思,那就分享一下啦