Administrator
发布于 2026-08-25 / 14 阅读
0
0

系列文章《Android 工程师的 100 篇进阶笔记》第 33 篇:Android 进程生命周期与 Low Memory Killer

上一篇讲了 Handler 消息机制,这篇往上一层——进程。你的 App 跑在哪个进程?系统怎么决定杀哪个进程?LMK(Low Memory Killer)的工作原理是什么?这些知识在做保活、后台任务、性能优化时都绕不开。

Android 进程优先级

系统把进程分为五个优先级层次,从高到低:

  1. 前台进程(Foreground):正在与用户交互的 Activity,或绑定了前台 Service,或正在执行 onReceive 的 BroadcastReceiver。

  2. 可见进程(Visible):Activity 可见但不在前台(比如弹了 Dialog 的 Activity)。

  3. 服务进程(Service):通过 startService 启动的后台 Service。

  4. 后台进程(Cached):用户不可见的 Activity(已 onStop),保存在 LRU 列表里。

  5. 空进程(Empty):没有任何活跃组件的进程,纯缓存。

系统在内存不足时从低优先级开始杀。前台进程几乎不会被杀(除非系统自己快撑不住了),空进程最先被清理。

oom_adj 值

Linux 用 oom_score_adj(范围 -1000 到 1000,越小越不容易被杀)来标记进程优先级。Android 在此基础上做了映射:

进程状态

oom_adj

说明

前台

0

用户正在交互

可见

100

可见但非前台

服务

200-500

后台 Service,根据存活时间递增

后台

600-900

缓存的 Activity

空

900+

纯空进程

你可以通过 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 通知体系的设计与最佳实践。


评论