前言
Android 平台上的内存泄露问题一直是令人头疼的挑战之一。内存泄露不仅可能拖慢应用性能,还可能导致应用崩溃或占用过多系统资源,进而影响用户体验,甚至带来隐私风险。

什么是内存泄露?
内存泄露是指在应用程序运行过程中,当一个不再需要的内存对象仍然被程序保留,无法被垃圾回收器(GC)释放,这些未释放的内存对象会持续占用系统内存资源,导致可用内存逐渐减少,最终可能导致应用性能下降、崩溃或者系统资源耗尽。
Leak Canary 简介
Leak Canary 是由 Square 公司开发的一个库,旨在帮助开发者尽早发现并解决应用中的内存泄露问题。它提供了一套简单易用的工具,可以在应用运行时检测内存泄露,并生成详细报告,帮助开发者定位内存泄露的源头。
主要特点
- 自动化检测:Leak Canary 会在应用运行时自动检测内存泄露,无需手动触发检测操作,大大简化了排查流程。
- 实时通知:一旦发现内存泄露,Leak Canary 会立即发出通知提醒开发者处理,帮助及时解决问题。
- 详细报告:Leak Canary 会生成详细报告,包括泄露对象类型、引用链、泄露发生位置等信息,帮助开发者准确定位内存泄露源头。
- 易于集成:Leak Canary 提供了简单易用的 API,方便开发者将其集成到现有 Android 项目中,并根据项目需求进行配置和定制。
示例
接下来,我们直接把 Leak Canary 集成到应用里,再通过一个模拟内存泄露的场景,演示它是如何捕获问题的。
1. 在 build.gradle 中添加依赖
debugImplementation("com.squareup.leakcanary:leakcanary-android:2.8.1")
debugImplementation 与 implementation 不同,它只在 debug 模式下编译以及最终打 debug 包时才会生效。
2. 模拟内存泄露
在 MainActivity 的伴生对象中创建一个 context 变量:

此时 IDE 会给出提示:不要将 Android 上下文类放在静态字段中,这会导致内存泄漏。原因是伴生对象中的字段最终会被编译为 Java 的静态字段。
如果将 context 存储到静态字段中,当 Activity 被销毁时,context 引用并不会被释放。举个例子:我们在 SecondActivity 中把 MainActivity.context 指向 SecondActivity 自身。

3. 运行触发内存泄漏
一旦 SecondActivity 被销毁,对它的引用仍然保留在 MainActivity 的伴生对象中。垃圾回收器会认为这个引用仍然需要,因此不会回收它;但实际上 SecondActivity 已经销毁,这个引用无法再被使用,内存泄露就这么发生了。
当发生内存泄漏时,Leak Canary 会以通知形式提醒开发者,并生成详细报告。
示例源码地址: https://github.com/germenwong/MemoryLeak
|