上一篇讲了 Handler 消息机制,这篇往上一层——进程。你的 App 跑在哪个进程?系统怎么决定杀哪个进程?LMK(Low Memory Killer)的工作原理是什么?这些知识在做保活、后台任务、性能优化时都绕不开。
Android 进程优先级
系统把进程分为五个优先级层次,从高到低:
前台进程(Foreground):正在与用户交互的 Activity,或绑定了前台 Service,或正在执行 onReceive 的 BroadcastReceiver。
可见进程(Visible):Activity 可见但不在前台(比如弹了 Dialog 的 Activity)。
服务进程(Service):通过 startService 启动的后台 Service。
后台进程(Cached):用户不可见的 Activity(已 onStop),保存在 LRU 列表里。
空进程(Empty):没有任何活跃组件的进程,纯缓存。
系统在内存不足时从低优先级开始杀。前台进程几乎不会被杀(除非系统自己快撑不住了),空进程最先被清理。
oom_adj 值
Linux 用 oom_score_adj(范围 -1000 到 1000,越小越不容易被杀)来标记进程优先级。Android 在此基础上做了映射:
你可以通过 cat /proc/<pid>/oom_score_adj 查看某个进程的当前值。开发时可以用这个命令验证你的 Service 优先级是否如预期。
LMK 的工作方式
Android 的 LMK(Low Memory Killer)是 Linux OOM Killer 的改良版。它在内核空间运行,当可用内存低于阈值时触发。
LMK 维护了几组内存阈值,每组对应一个 oom_adj 级别:
# 示例(不同设备不同)
# 临界阈值 -> 对应 adj 级别
minfree: 18432, 23040, 27648, 32256, 36864, 40960 (KB)
oom_adj: 0, 100, 200, 300, 400, 900
当空闲内存低于 18432 KB 时,杀 adj >= 0 的进程(也就是全部,极端情况)。低于 23040 KB 时杀 adj >= 100 的。依此类推。
这套机制保证了前台进程尽量活到最后。
ActivityManager 的进程调度
AMS(ActivityManagerService)负责动态调整进程的 oom_adj:
Activity 从 onResume 到 onPause → adj 从 0 调到 100
Service 调 startForeground → adj 降到 0-100
绑定 Service 的客户端进程的 adj 不低于 Service 的 adj
ContentProvider 的客户端进程 adj 不低于 Provider 进程
理解这些规则对做进程保活很重要:不是你 startService 了就不会被杀,关键看 adj 级别。
后台保活的真相
Google 从 Android 8 开始大幅限制后台 Service,12 之后更严格。常见的保活策略和它们的实际效果:
1. 前台 Service + 通知
startForeground(1, notification)
把 Service 提升到前台进程级别。唯一靠谱的保活方式,但必须显示通知,用户可以看到。
2. WorkManager
WorkManager.getInstance(context)
.enqueueUniqueWork("keep_alive", ExistingWorkPolicy.REPLACE, request)
WorkManager 确保任务最终执行,但不保证进程持续存活。系统会选择合适时机拉起进程。
3. JobScheduler
类似 WorkManager,系统调度。Android 9+ 有最小间隔限制(不能太频繁)。
4. 双进程互拉 / 账号同步
国产 ROM 早期有效,但 MIUI、EMUI 等定制系统已经封杀。Google 原生系统也限制同步 API 的频率。不推荐。
说实话,2024 年以后纯靠技术手段做"永不被杀"基本不可能了。正确思路是:接受进程会被杀的事实,用 WorkManager 保证任务能重跑,用 Foreground Service 保证运行期间不被杀,用数据持久化保证恢复。
多进程架构实践
有些场景需要多进程:
大内存模块隔离:视频播放、WebView 等内存大户放独立进程,用完直接杀进程释放
保活」辅助模块:Push SDK 放独立进程,降低被一起杀的概率
崩溃隔离:不稳定模块独立进程,崩了不影响主进程
<!-- AndroidManifest.xml -->
<service
android:name=".VideoService"
android:process=":video" />
<activity
android:name=".WebActivity"
android:process=":web" />
多进程的代价:进程间通信开销大(要走 Binder),Application onCreate 会在每个进程都调一次(需要区分进程做不同初始化),调试更复杂。
小结
理解进程优先级和 LMK 机制,是做后台任务、保活、性能优化的基础。核心记住:前台进程优先级最高,空进程最先被杀;保活不要迷信黑科技,用 Foreground Service + WorkManager + 数据持久化的组合拳才是正道。
下一篇聊聊 Android 通知体系的设计与最佳实践。