systemd-oomd仅依据unit文件中的OOMScoreAdjust=值决策,忽略/proc/PID/oom_score_adj手动修改;需重启服务生效,并注意slice层级覆盖、容器/fork子进程导致的失效及ProtectProc影响。

systemd-oomd 不读 /proc/PID/oom_score_adj,只认 unit 静态配置
这是最常被误解的一点:你用 echo -500 > /proc/1234/oom_score_adj 手动改了值,systemd-oomd 完全无视。它只从 systemd unit 文件里读 OOMScoreAdjust= 这个字段——哪怕进程已运行,只要没重启服务,改动就白费。
- 必须执行
sudo systemctl daemon-reload && sudo systemctl restart myapp.service(仅daemon-reload不够) - 验证是否生效:
systemctl show -p OOMScoreAdjust myapp.service,输出应为OOMScoreAdjust=-500 - 若看到
OOMScoreAdjust=0,说明配置没加载、拼写错误(比如写成OOMScoreAdjustment)、或被父 slice 覆盖(见下一条)
slice 层级覆盖导致 OOMScoreAdjust 被静默重置
假设你给 myapp.service 设了 OOMScoreAdjust=-900,但它跑在 workload.slice 下,而该 slice 自己设了 OOMScoreAdjust=0,那么 oomd 实际采用的是 0 —— 因为 oomd 优先取“最近的、启用 MemoryAccounting 的 cgroup 级别”的值,不是取 service 最小值。
- 查进程真实归属:
cat /proc/PID/cgroup | grep -E '(slice|service)' - 统一管理策略:要么全在
myapp.service里设OOMScoreAdjust+MemoryAccounting=yes,要么在workload.slice级别统一设,不要混用 - 禁用 slice 级干扰:
sudo systemctl set-property workload.slice OOMScoreAdjust=(留空即清除继承)
/etc/systemd/oomd.conf 几乎不控制优先级逻辑
别在 oomd.conf 里找 DefaultOOMScoreAdjust 或类似字段——它根本不存在。这个文件只管全局开关和压力阈值,比如 ManagedOOMMemPressureLimit=60,但完全不参与进程打分排序。
-
oomd.conf可配项极少:LogLevel、ManagedOOM、ManagedOOMMemPressureLimit、ManagedOOMSwap(建议设为auto) - 优先级决策全由 unit 配置驱动,
oomd.conf不影响OOMScoreAdjust解析逻辑 - 想调高日志粒度看 oomd 怎么选进程?加
Environment=SYSTEMD_OOMD_LOG_LEVEL=4到systemd-oomdservice,再journalctl -u systemd-oomd -f
容器、fork 子进程、ProtectProc 会直接让 OOMScoreAdjust 失效
Java 应用启动后 fork 出多个 JVM 子进程,或 Docker/runc 容器默认把 oom_score_adj 设为 -999,都会导致 systemd 单元设置的 OOMScoreAdjust 在子进程上丢失。
- Java 类服务务必加:
OOMScoreAdjust=-500+ProtectProc=no(否则子进程被锁定为 0) - 容器场景慎用
ProtectProc,且确认 runtime 没覆盖 oom_score_adj(runc 默认设 -999,会压倒 unit 设置) - Type 必须匹配:若用
Type=forking,确保PIDFile=正确指向主进程 PID;Type=simple更稳妥
cat /proc/PID/cgroup 和 systemctl show -p OOMScoreAdjust 这两行命令,比翻十页文档都管用。










