OOM 机制与实现详解
源码路径:
rk3588/kernel-6.1/mm/oom_kill.c
内核版本:Linux 6.1(RK3588)
文档目录:linuxDoc/mm/
目录
一、原理
1.1 何时触发 OOM
当 __alloc_pages 慢路径 在以下手段后仍失败:
- direct reclaim
- compaction
- (可能)多次重试
则调用 __alloc_pages_may_oom() → out_of_memory()。
OOM 不是「物理 RAM 为 0」,而是 在给定 gfp/zone/cpuset 约束下无法满足分配。
1.2 设计目标
在系统崩溃与随机杀进程之间,选择 oom_score 最高的进程终止,释放其 RSS + 页表 + 缓存引用,使后续分配成功。
1.3 与回收的区别
| 机制 | 行为 |
|---|---|
| reclaim | 回收 可丢弃 的 cache 或 swap 匿名页 |
| OOM | 终止 整个进程,回收其独占匿名页等 |
二、实现方式
2.1 入口:out_of_memory()
1 | bool out_of_memory(struct oom_control *oc) |
2.2 struct oom_control
记录本次 OOM 上下文:
gfp_mask、order、zonelistmemcg(若为 cgroup OOM)chosen:选中 victimconstraint:NUMA / cpuset / policy 限制
2.3 选择 victim:select_bad_process
遍历进程(for_each_process 或 memcg 子树):
- 计算
oom_badness:RSS、swap、调度类、硬件损坏等 - 加上
oom_score_adj(/proc/<pid>/oom_score_adj,-1000 永不杀) - 跳过 内核线程、
PF_KTHREAD、OOM_SCORE_ADJ_MIN等
2.4 杀进程:oom_kill_process
mark_oom_victim:设置TIF_MEMDIE等- 发送 SIGKILL(或依赖 oom reaper)
oom_reaper内核线程加速释放 victim 的 mm(unmap、释放页)
2.5 分配进程优先退出
若当前进程 task_will_free_mem(已有 SIGKILL、正在 exit),直接选为 victim,便于 快速释放 而不搜全局。
2.6 pagefault OOM
pagefault_out_of_memory():缺页路径无 gfp 上下文,主要处理 memcg OOM;全局 OOM 仍由分配上下文触发。
2.7 panic 路径
panic_on_oom:OOM 时内核 panic- 无可杀进程:
panic("System is deadlocked on memory")
三、关键数据结构与接口
| 接口 | 说明 |
|---|---|
out_of_memory |
全局/约束 OOM 入口 |
register_oom_notifier |
第三方在杀进程前尝试释放内存 |
oom_killer_disable/enable |
暂停 OOM(危险) |
/proc/<pid>/oom_score |
只读分数 |
四、memcg OOM 与全局 OOM
| 类型 | 范围 | 典型场景 |
|---|---|---|
| 全局 OOM | 全系统 | 物理内存耗尽 |
| memcg OOM | 超过 cgroup limit | 容器/Android 应用组 |
memcg 路径 mem_cgroup_out_of_memory → 仍调用 out_of_memory 但 is_memcg_oom(oc) 为真,仅杀组内进程。
五、RK3588 平台说明
- 编码服务 + 多客户端:建议用 memcg 限制单应用,避免一次全局 OOM 杀掉编码守护进程。
- lmkd(Android)根据 adj 与 vmpressure 杀应用,与内核 OOM 互补。
- 调
oom_score_adj保护关键进程(如mediaserver、自定义编码器)。
六、调试与观测
| 手段 | 说明 |
|---|---|
dmesg |
Out of memory: Kill process ... |
/proc/<pid>/oom_score_adj |
调整优先级 |
sysctl vm.panic_on_oom |
2=panic |
sysctl vm.oom_kill_allocating_task |
杀当前分配者 |
附录:源码索引
| 主题 | 文件 | 约略行号 |
|---|---|---|
| out_of_memory | oom_kill.c | 1106 |
| oom_badness | oom_kill.c | 搜索 select_bad |
| pagefault OOM | oom_kill.c | 1185 |
正在加载留言…