核心是设置--memory硬限制划定安全边界,并用--oom-score-adj调整优先级;无硬限制时优先级无效,内核仅在超限时触发OOM Killer评估。

在 Docker 中配置 OOM 控制策略,核心是两件事:一是用内存限制划定“安全边界”,二是通过优先级调整决定“谁先被杀”。不设限或只调优先级,都解决不了根本问题。
必须配合 --memory 设置硬限制
单独设置 OOM 优先级无效。Linux 内核只在容器实际内存使用超出 --memory 限定值时,才触发 OOM Killer 评估。没这个上限,oom_score_adj 就失去判断依据。
- --memory=2g:强制容器最多用 2GB 物理内存,超限即进入 OOM 判定流程
- --memory-swap=2g:禁用 swap,避免延迟性 OOM(推荐生产环境使用)
- --memory-reservation=1.5g:软限制,在内存紧张时 Docker 会主动回收超出该值的部分,降低 OOM 触发概率
用 --oom-score-adj 调整回收优先级
Docker 20.10+ 支持直接传参控制内核评分,数值越低越难被杀,范围 -1000 到 +1000:
- --oom-score-adj=-500:适合数据库、API 等核心服务,显著降低被终止风险
- --oom-score-adj=0:默认值,与宿主机普通进程一致
- --oom-score-adj=300:适合批处理、日志聚合等临时任务,更早被回收
- --oom-score-adj=-1000:仅限特权容器且内核支持,可近乎禁用 OOM Killer(慎用)
验证方式:docker exec 容器名 cat /proc/1/oom_score_adj
避免常见配置陷阱
很多 OOM 并非资源不够,而是配置反模式导致:
- Java 容器未设 JVM 堆上限(如 -Xmx512m),JVM 自动申请远超容器 limit 的内存
- 忽略 /dev/shm 和 tmpfs 占用,默认 64MB 不够用,大模型或高并发场景易撑爆
- 边缘设备(树莓派、Jetson)无 swap,--memory-swap=-1 会放大 OOM 风险,应显式设为与 memory 相同
- 用 docker stats 实时看 MEM USAGE / LIMIT,接近 95% 就该预警,别等 exit code=137 才反应
Compos e 中的等效写法
在 docker-compose.yml 里不能直接写 --oom-score-adj,但可通过 sysctls 或 mem_limit + oom_score_adj 组合实现:
- 内存限制写在 deploy.resources.limits.memory
- OOM 优先级需加 sysctls: {"vm.oom_kill": "0"}(禁用)或配合启动脚本写入 /proc/1/oom_score_adj(动态生效)
- 更稳妥的做法:改用 docker run 启动关键服务,确保 --oom-score-adj 生效











