第1章 / 30章:Flow泄漏现象识别 —— 内存持续增长与协程不取消

定位泄漏的前提是感知异常。用户反馈、监控告警或开发过程中的直觉,往往是排查的起点。本章系统梳理Flow泄漏的五大典型表象,并建立从表象到工具的快速映射关系,协助你在第一时间确认问题的存在。

Flow泄漏现象识别故障树 可疑Flow泄漏 内存持续增长 协程不取消 GC无法回收 应用卡顿 OOM风险 dumpsys meminfo Coroutine Debug Heap Dump / MAT Systrace Crash监控 锯齿状阶梯上升 Scope外存活协程 GC Root持有引用 UI线程Block/ANR OutOfMemoryError 说明:现象识别是排查流程的输入,精准的现象描述决定了后续排查路径的选择。建议同时在宏观(dumpsys)和微观(Profiler)两个维度进行交叉验证。

1.1 五大核心表象与检测工具映射

现象核心特征首选检测手段危险等级
内存持续增长Memory Profiler中呈现锯齿状阶梯上升,GC后无法回落至基线adb shell dumpsys / Profiler高
协程不取消ViewModel onCleared或Activity onDestroy后,协程Job仍处于Active状态Kotlin Coroutines Debug插件严重
GC无法回收Heap Dump中发现FlowCollector或Continuation对象被GC Root强引用持有Heap Dump + MAT严重
应用卡顿主线程Choreographer频繁跳帧,Systrace显示Flow发射任务阻塞UI线程Systrace / CPU Profiler中
OOM风险因Flow缓存或内部队列积压导致OutOfMemoryError崩溃Crash Upload / Bugly灾难

1.2 实战现象识别流程

步骤一:宏观内存检查(快速排除法)

通过adb命令直接读取应用整体内存状态,持续观察特定指标的波动。

adb shell dumpsys meminfo com.example.leakyapp | grep -E "TOTAL|PSS"

判断规则:反复执行3次(每次间隔5秒),如果TOTAL PSS持续增长且单次增量超过512KB,基本可以判定存在内存泄漏嫌疑。

步骤二:协程存活检查(溯源协程)

利用IDE的调试功能直接查看当前进程中所有存活的协程及其所属Scope。

1. 在Android Studio中运行应用。
2. 打开 Debug 工具窗口(Alt + Shift + F9)。
3. 找到 Kotlin Coroutines 标签页。
4. 展开列表,搜索 "flow" 关键字。
5. 检查是否有协程挂载在已销毁的 Scope(如 onDestroy 后的 ActivityScope)上。

典型泄漏日志特征:协程名称中包含flow,并且其所在的Scope处于Empty状态(表示父Scope已被GC回收,但协程仍存活)。

步骤三:GC回收验证(最具说服力)

强行触发GC并抓取Heap Dump,分析引用路径。

// 强行触发GC
adb shell am broadcast -a android.intent.action.DISMISS_KEYBOARD_SHORTCUTS

// 手动触发GC(Profiler中点击“垃圾桶”图标)
// 等待1分钟后抓取Heap Dump

// 使用MAT或Android Studio自带Profiler分析
// 搜索 "FlowCollector" 或 "SafeCollector" 查看GC Root路径

判断规则:如果Heap Dump中 SafeCollector 或 FlowCollector 实例数超过3个,并且每个实例都有强引用路径(如 Fragment → ViewModel → Job → Continuation → FlowCollector),即可确认为Flow泄漏。

避坑:仅凭堆内存持续增长不能直接判定为Flow泄漏,需要结合GC是否能够回收以及协程是否取消综合判断。部分原生内存(如Bitmap)增长并非Flow泄漏。后续章节将对此进行交叉验证。

1.3 泄漏现象快速排查决策表

你遇到的是什么情况?
├── 应用不卡顿,但内存不断涨
│   └── ➔ 查看协程是否活跃(Debug Plugin) ➔ 进入第2章
├── 应用卡顿明显,甚至有ANR
│   └── ➔ 查看主线程堆栈(Systrace) ➔ 是否在collect?
│       ├── 是 ➔ Flow泄漏导致主线程阻塞
│       └── 否 ➔ 检查其他主线程耗时操作
├── OOM崩溃
│   └── ➔ 查看崩溃堆栈是否有Flow相关方法
│       ├── 是 ➔ 进入第3章深入分析
│       └── 否 ➔ 检查其他OOM原因(如大图加载)
├── 明显感觉GC频繁(Logcat: GC_FOR_ALLOC)
│   └── ➔ 抓取Heap Dump查看大量FlowCollector实例 ➔ 进入第4章
└── 无感知异常,但监控告警内存超标
    └── ➔ 使用adb dumpsys定时采集数据 ➔ 进入第2章

1.4 小结