第2章 问题分类:崩溃、卡死、内存泄漏、功耗异常、服务被杀、优先级错乱
后台任务问题的根源通常可归结为六大类别。准确识别分类是后续采集、定位与修复的基石。本章按照“现象识别 → 数据采集 → 原因定位 → 修复动作 → 复测 → 预防”的闭环流程,逐一展开每个分类的实战要点。
2.1 现象识别
不同问题在设备上表现出差异明显的症状。以下是六大类问题的典型现象速查表:
| 问题分类 | 典型用户可见现象 | 系统级征兆 |
|---|---|---|
| 崩溃 | 应用突然退出、出现“应用已停止”对话框 | logcat 中可见 FATAL EXCEPTION、signal 11/6 |
| 卡死 | 屏幕无响应、触摸事件延迟超过 5 秒、ANR 弹窗 | logcat 输出 ANR in ...,traces.txt 记录主线程阻塞 |
| 内存泄漏 | 应用随使用时间越来越卡,最终 OOM 被杀死 | dumpsys meminfo 显示 PSS 持续增长,GC 频繁 |
| 功耗异常 | 设备发烫、待机耗电快、电池统计显示该应用唤醒频繁 | dumpsys battery_stats 显示部分 wakelock 持有时长异常 |
| 服务被杀 | 后台功能(如音乐播放、定位上报)无故中断 | logcat 出现 Process xx has died / Scheduling restart |
| 优先级错乱 | 前台应用反被后台应用抢占 CPU/网络资源,前台卡顿 | top 命令显示后台线程优先级高于前台,或 cgroup 归属错误 |
识别技巧: 当用户报告“应用闪退”时,优先检查崩溃日志;若描述为“点不动”,则聚焦卡死回溯。用现象绑定分类,能大幅缩小排查范围。
2.2 数据采集
确认分类后,立即用 adb shell 命令采集现场证据。下表列出针对每个分类的首选采集命令与输出焦点:
| 问题分类 | 核心采集命令 | 关键数据 |
|---|---|---|
| 崩溃 | | Java/Kotlin 异常栈、native 信号、so 加载信息 |
| 卡死 | | 主线程堆栈、等待锁、Binder 调用超时 |
| 内存泄漏 | | Native Heap、Dalvik Heap、Graphics 内存节节攀升 |
| 功耗异常 | | Wakelock 统计、网络流量、传感器使用时长 |
| 服务被杀 | | 进程优先级、adj 值变化、最后一次被杀原因 |
| 优先级错乱 | | 线程优先级(PR/NI)、CPU 占比、cgroup 路径 |
注意: 采集应在问题复现后立即执行,避免关键数据被系统清理。对于服务被杀,优先保留一刻钟内的完整 logcat 记录。
2.3 原因定位
汇总采集数据后,通过故障树快速锁定根因。下图展示了六大分类及其对应的最常见直接原因:
定位口诀: 崩溃看堆栈,卡死找 trace,内存盯 PSS,功耗查 wakelock,服务抓 adj,优先级扒 cgroup。
2.4 修复动作
根据分类采取针对性修复方案,以下为每类的标准修复方向:
- 崩溃:修复 null-check、try-catch 异常、升级依赖库版本、处理 native 层指针。
- 卡死:将 IO 操作移出主线程,使用
HandlerThread/Coroutine;减少锁竞争,避免 Binder 阻塞。 - 内存泄漏:使用 WeakReference 持有 Activity 或 Context;在 onDestroy 中移除回调、取消注册、清空集合。
- 功耗异常:确保 wakelock 成对 acquire/release;合并网络请求,使用 WorkManager 延迟后台任务。
- 服务被杀:将 Service 提升为前台服务(Foreground Service),设置合理通知优先级;控制内存占用,避免被 LMK 选中。
- 优先级错乱:检查应用是否越权设置线程优先级,动态设置
Process.setThreadPriority();确保前台 Activity 所在进程 oom_adj 处于可见范围。
警告: 修复服务被杀时,滥用前台服务会触发权限警告(Android 14+ 需启动时立即显示通知),应优先降低内存消耗。
2.5 复测
修复后必须通过以下手段确认问题不再复现:
- 安装修复版 APK,使用
adb shell monkey -p <package> 500进行随机操作测试,同时观察 logcat 中是否仍有异常日志。 - 针对卡死,使用
adb shell dumpsys activity processes | grep "procState: FOREGROUND"确保主线程响应窗口不超时。 - 针对内存泄漏,运行 20 分钟后台场景后重复
adb shell dumpsys meminfo对比 PSS 是否趋于稳定。 - 针对功耗异常,使用
adb shell dumpsys batterystats对比修复前后 wakelock 总时长。 - 针对服务被杀,在低内存环境下(
adb shell am send-trim-memory <pid> COMPLETE)验证服务是否存活。 - 针对优先级错乱,执行高负载后台任务时通过
adb shell top -d 1 -n 3观察前台应用 CPU 占比不被抢占。
2.6 预防
将以下最佳实践纳入开发规范与 CI 门禁:
- 崩溃预防:代码扫描(SpotBugs / Lint)、单元测试覆盖临界路径、线上集成 Crash SDK 实时上报。
- 卡死预防:StrictMode 在调试期检测主线程磁盘/网络操作;使用 ANR 监控工具主动抓取 traces。
- 内存泄漏预防:引入 LeakCanary 自动化检测,每日构建回归对比 baseline。
- 功耗预防:使用 Battery Historian 分析历史曲线,对每个新增 wakelock 代码走读审核。
- 服务被杀预防:监控进程 oom_adj 值,保持在
VISIBLE_APP以上;做好 Service 断线重连机制。 - 优先级预防:禁止在非 root 设备上随意修改线程优先级,使用 Android 推荐的优先等级规范。
持续改进: 建议在 Bug 管理系统内将每个问题标记为上述六类之一,累积成分类统计仪表盘,定期对 Top 类型发起专项治理。