oom_adj 与进程优先级:生死的排序依据
2026/8/9大约 4 分钟进程与内存管理Android 14oom_adj进程优先级LMK
oom_adj 与进程优先级:生死的排序依据
上一章建立了全景。这一章进入决策链第一环,回答:AMS 怎么给进程定级,oom_score_adj 怎么被写入,各档位代表什么?
/proc/<pid>/oom_score_adj 虽然是内核接口,值却主要由 AMS 的 OomAdjuster 根据前台组件、 可见性、服务绑定和缓存状态计算。数值越大,进程在内存压力下越靠前成为候选。
oom_score_adj 由 Framework 计算并写入
| 常见误解 | 正确理解 |
|---|---|
| oom_adj 是内核自己算的 | AMS 按组件状态计算并写入,内核只提供接口 |
| 数值越小越容易被杀 | 数值越大越容易被杀;前台可调整范围为 0 附近,后台趋近 1000 |
| 杀进程只看 oom_adj | 还要叠加内存占用与 cgroup 分组,adj 决定顺序而非唯一依据 |
核心结论
- AMS 根据组件状态与进程类型计算 adj,写入
oom_score_adj。 - 典型档位:前台 0、可见进程、服务、缓存后台进程逐级增大。
- 内核 oom_score = oom_score_adj + 内存占用贡献,两个维度共同决定分数。
- lmkd 主要按 adj 顺序回收;内核 OOM 只在极端情况下兜底。
- 进程状态变化时 adj 会重新计算并更新,正在使用中的进程不会瞬间被杀。
档位与写入主链
逐步解释:
- 状态变化:应用切后台、服务启动、弹窗可见等都会触发进程状态更新。
- 计算 adj:OomAdjuster 按规则算出新档位。
- 写入内核:通过进程接口更新
oom_score_adj。 - 打分:内核把 adj 与内存占用合并成 oom_score。
- 回收:lmkd 按顺序回收,内核 OOM 兜底。
典型档位速查
| 档位 | oom_score_adj 量级 | 代表进程 |
|---|---|---|
| 前台(FOREGROUND_APP_ADJ) | 0 附近 | 当前交互应用 |
| 可见(VISIBLE_APP_ADJ) | 100 附近 | 可见但非前台 |
| 服务(SERVICE_ADJ) | 500 附近 | 后台服务 |
| 缓存(CACHED_APP_MIN_ADJ) | 900+ | 后台缓存进程 |
具体数值以 Android 14 源码常量为准;理解顺序比背数字更重要——前台优先保住,缓存 进程最先牺牲。
源码证据
阅读目标:确认 adj 计算与写入入口。
正文指针:OomAdjuster.java 的计算逻辑;ProcessList.java 中的 adj 常量与写入调用。
// ProcessList.java(伪代码,行号以 r75 为准)
static final int FOREGROUND_APP_ADJ = 0;
static final int VISIBLE_APP_ADJ = 100;
static final int CACHED_APP_MIN_ADJ = 900;
// OomAdjuster 计算结果写入 /proc/<pid>/oom_score_adj这段代码证明: 档位由 Framework 定义并写入;内核只消费这个值。这也是“Android 的 进程生死由系统决定”的代码依据。
验证与排障
环境:开发设备或模拟器;以下命令不需要 root。
adb shell cat /proc/<pid>/oom_score_adj
adb shell dumpsys activity oom
adb shell ps -A | grep <包名>oom_score_adj 看当前档位;dumpsys activity oom 列出进程与 adj 的对应关系; ps 找进程 pid。应用“一进后台就被杀”时,先看它的 adj 是否处于缓存档位,再查为什么 被系统认定为可回收。
常见误区
- “adj 是内核算的”:是 AMS 计算并写入。
- “adj 越小越安全、越大越危险”:对,方向别记反。
- “杀进程只看 adj”:还要看内存占用与 cgroup。
- “adj 一旦写入不变”:状态变化会重新计算更新。
延伸问题
- 为什么前台应用 adj 也可能不是 0(如正在启动)?
oom_score与oom_score_adj的区别是什么?- 厂商如何通过配置调整缓存进程数量?
- adj 与进程优先级(priority)是两个概念,区别在哪?
源码入口
| 文件 | 关键位置 | 作用 |
|---|---|---|
ProcessList.java | adj 常量 | 档位定义 |
OomAdjuster.java | adj 计算 | 优先级计算 |
ProcessList.java | 写入调用 | 更新 oom_score_adj |
/proc/<pid>/oom_score_adj | 内核接口 | 数值消费 |
公共路径:frameworks/base/services/core/java/com/android/server/am/。行号以 r75 检索为准。
谁消费这些优先级并执行查杀,见 lmkd。