systemd-oomd不尊重oom_score_adj值,包括-1000;其豁免仅依赖OOMPrevent=true和cgroup路径白名单,与内核OOM killer无关。

当进程的 oom_score_adj = -1000 却仍被 systemd-oomd 杀掉,说明它没有被完全豁免——因为 systemd-oomd **不尊重 oom_score_adj 的值**,包括 -1000。
systemd-oomd 完全忽略 oom_score_adj
systemd-oomd 是 systemd 自研的用户态 OOM 管理器,设计上就绕过了内核的 OOM killer 逻辑。它有自己的内存压力评估机制(基于 cgroup v2 的 memory.pressure、memory.current、swap usage 等),不读取也不应用 /proc/[pid]/oom_score_adj。所以无论你设成 -1000 还是 0,对 systemd-oomd 都无效。
真正起作用的是 cgroup 层级与 oom\_prevent 设置
systemd-oomd 的豁免逻辑只认两个东西:
-
cgroup 路径是否在白名单中:默认只监控
/sys/fs/cgroup/system.slice/和/sys/fs/cgroup/user.slice/下的 service scope;/sys/fs/cgroup/init.scope(即 PID 1)和/sys/fs/cgroup/system.slice/init.service等关键路径会被自动排除 -
是否显式设置了
OOMScoreAdjust=-1000+OOMPolicy=continue(或kill)并启用OOMPrevent=true:
–OOMPrevent=true是关键开关,它会让systemd-oomd主动跳过该 unit 及其所有子 cgroup
– 仅设OOMScoreAdjust不生效;必须配合OOMPrevent=true
如何让关键进程真正免于被 systemd-oomd 杀掉
以一个需要保护的 service(如数据库)为例:
- 编辑服务 unit 文件:
sudo systemctl edit mydb.service - 写入以下内容:
[Service] OOMPrevent=true OOMScoreAdjust=-1000 OOMPolicy=continue
- 重载并重启:
sudo systemctl daemon-reload && sudo systemctl restart mydb.service - 验证:
systemctl show mydb.service | grep -E "(OOMPrevent|OOMScoreAdjust)",确认输出为OOMPrevent=yes和OOMScoreAdjust=-1000 - 检查 cgroup 路径是否在
systemd-oomd监控范围内:systemctl status mydb.service | grep "CGroup:",确保不在/init.scope或其他被硬编码排除的路径下(否则OOMPrevent也无意义)
注意 systemd-oomd 的默认行为边界
systemd-oomd 默认不监控 root.slice、machine.slice、docker/k8s 容器 cgroup(除非手动配置规则)。如果你的服务跑在容器里,或被放在 root.slice 下(例如用 systemd-run --scope --scope-property=Slice=root.slice 启动),那它压根不会被 systemd-oomd 看到——此时看到的 OOM kill 很可能来自内核原生 OOM killer,而非 systemd-oomd。
可查日志确认来源:journalctl -u systemd-oomd -n 50(有日志则为 systemd-oomd 触发);若无,再查 dmesg -T | grep -i "killed process"(内核 OOM 输出)。










