1. 内存泄漏概述:什么是内存泄漏、为什么重要
说实话,干了这么多年Android性能优化,我最怕听到的就是线上用户反馈“App用着用着突然闪退”或者“点个按钮等半天没反应”。排查到最后,十有八九跟内存泄漏有关。内存泄漏这东西,说白了就是本该被回收的对象,却因为某些引用一直活着,像下水道里卡住的头发丝——越积越多,最后彻底堵死。
1.1 到底什么是内存泄漏?
官方定义很拗口:“不再需要的对象被垃圾回收器(GC)判定为可达而无法回收”。我换个说法:你用完一把螺丝刀,随手放回工具箱。但如果有人一直握着它不放,你想用也用不了,工具箱里还多占一个位置。程序里的对象也是这个道理——当某个Activity退出后,它的实例本该被GC清理,但如果有静态变量或匿名内部类持有它的引用,它就永远“赖着不走”。
举个例子,我几年前优化一个社交App的“个人主页”时发现,用户反复进入退出该页面,内存占用就只升不降。用MAT一分析——原来Fragment里有个匿名Handler,发送了一个延迟消息,而这个Handler隐式持有外部Activity的引用。Activity销毁后,消息队列里还挂着这个Handler,Activity死活没法回收。你看看,这就是典型的“隐式泄漏”。
1.2 内存泄漏的常见“元凶”
我个人在实践中总结过一张表,基本涵盖了90%的Android泄漏场景:
| 泄漏类型 | 根本原因 | 典型实例 | 解决方案(一句话) |
|---|---|---|---|
| 静态变量泄漏 | static字段持有Activity/Context | 单例保存Activity引用 | 改用Application Context或弱引用 |
| 非静态内部类泄漏 | 内部类隐式持有外部类引用 | 匿名Runnable、Handler | 使用静态内部类+弱引用 |
| 资源未关闭 | Cursor、Stream、IO忘记close | 数据库查询后未关闭Cursor | try-with-resources或在finally中关闭 |
| 注册未注销 | BroadcastReceiver、EventBus、观察者未unregister | Activity中注册了动态广播 | 在onDestroy中反注册 |
| 集合类泄漏 | 对象放入集合后不再移除 | HashMap中的Key长期存活 | 使用WeakHashMap或及时remove |
你可能会问:“这些看起来都是基础知识点,写过Android的都知道啊?” 嗯,道理都懂,但在复杂业务里很容易被忽视。我曾经在优化一个视频编辑App时,发现一个工具类里有个static的ArrayList用来缓存历史操作,结果随着用户不断撤销重做,这个List无限膨胀,最后直接OOM。你看,理论落到实践,就是另一回事了。
1.3 为什么内存泄漏“必须重视”?
很多人觉得“内存泄漏嘛,大不了GC多回收几次”。可实际上,泄漏的代价远不止堆空间被占。我梳理了三个主要影响:
- 直接OOM: 堆内存被泄漏对象吃光,系统直接杀掉进程。用户感知就是闪退。
- 触发ANR: 堆空间紧张时,GC会频繁触发Full GC,每次停顿几十到几百毫秒,这些停顿可能就卡在UI线程上。用户点了个按钮,等了5秒没反应,系统弹出“应用无响应”。
- 性能雪崩: 内存不足触发系统LMK(Low Memory Killer)杀后台进程,杀完又重启,来回折腾,手机发热、耗电快。
1.4 内存泄漏的“蝴蝶效应”
我把从泄漏发生到最后造成卡死/ANR的完整链条画了一张图,你看一眼应该就全明白了:
你看这个链条:业务结束后对象本该死,但被意外引用拖住 → GC觉得它“还活着” → 堆内存只增不减 → 系统为了腾空间频繁GC(卡顿) → 堆吃满后直接OOM,或者长时间GC冻结UI线程导致ANR。我当年那个视频播放器的ANR,就是第4步到第6步这条路径。
1.5 快速自检:你写的代码有没有泄漏风险?
分享一个我平时做Code Review时检查的checklist:
- 静态变量或单例里有没有Activity/Context/View引用?
- 匿名内部类(尤其是Runnable、Handler)是否可能在对象销毁后仍在执行?
- 广播、观察者、callback有没有成对注册/注销?
- Bitmap、File、Cursor用完有没有关闭?
- 集合类是否无限增长而没有清理机制?
1.6 本章要点整理
好,咱们把这一章的核心记下来:
- 内存泄漏 = 无用对象被GC误认为有用,本质是引用链没有断开。
- 泄漏直接导致堆内存膨胀,进而引发OOM、ANR、卡顿这三种最让用户抓狂的问题。
- 最常见的场景:静态变量、内部类、资源未关闭、注册未注销、集合类。
- 排查手段:借助Memory Profiler、MAT、LeakCanary,结合人工Code Review。