OOM Killer 是内核保命机制,非 bug;无法“解决触发”,只能控制谁被杀、何时杀及提前预警,关键在于调低关键进程 oom_score_adj 值、配置 memory 限制并监控内存压力。

根本没法“解决触发”,只能控制谁被杀、什么时候杀、杀之前先预警。 OOM Killer 是内核保命机制,不是 bug;关掉它等于让系统在内存耗尽时直接卡死或 panic。真正要做的,是让关键业务进程不被选中,同时提前发现内存压力,而不是等 Killed process 出现在日志里才反应。
怎么查确认真是 OOM Killer 干的
别猜,先验证。很多“内存不足”其实是缓存占位高、swap 没开、或进程假死,不是真 OOM:
- 运行
dmesg | grep -i "out of memory",出现Killed process XXX (mysqld)才是 OOM Killer 动手了 - 检查
/var/log/messages或/var/log/syslog,搜oom或Out of memory - 对比时间点:用
sar -r -f /var/log/sa/sa$(date -d yesterday +%d)看当时kbmemfree是否真的逼近 0,且kbmemused持续高位 - 注意陷阱:
free -h显示available很低但buff/cache很高,大概率是 Linux 在做合理缓存,不等于 OOM 条件成立
怎么让 mysqld / java / yasdb 这类进程免于被杀
核心是调低它的 oom_score_adj 值——这个值越负,内核越不愿意杀它。默认是 0,设成 -1000 就几乎免疫(-1000 是下限):
- 临时生效(重启后失效):
echo -1000 > /proc/$(pgrep -f "mysqld")/oom_score_adj(需 root) - 永久生效(推荐):写进 systemd service 文件,在
[Service]段加一行:OOMScoreAdjust=-1000,然后systemctl daemon-reload && systemctl restart mysqld - 别用
echo -1000 > /proc/PID/oom_score_adj对已启动的 Java 进程硬改——JVM 启动后子进程 PID 可能漂移,且没做 cgroup 隔离的话,子线程仍可能被单独评分 - 注意权限:非 root 用户无法写
/proc/PID/oom_score_adj,必须用 sudo 或改 systemd 配置
为什么调了 oom_score_adj 还被杀了
常见原因不是配置无效,而是机制没对齐:
-
vm.overcommit_memory = 2时,内核会严格按物理内存+swap×overcommit_ratio(默认 50%)限制总分配量。此时 OOM Killer 不会触发,而是malloc直接返回 NULL,应用自己 crash,日志里看不到Killed process——你看到的“被杀”其实是应用因分配失败退出,不是内核杀的 - 进程在容器里(如 Docker/K8s),
oom_score_adj要在容器启动时通过--oom-score-adj传入,宿主机上改/proc无效 - 用了 cgroup v2,
oom_score_adj会被 cgroup 的memory.oom.group和memory.low覆盖,优先级更高 - 进程本身有内存泄漏,
oom_score_adj只让它“活得久一点”,但持续涨内存最终仍会拖垮整个 cgroup 或节点
怎么避免走到被杀那一步
靠“豁免”是兜底,靠监控和约束才是正解:
- 给关键服务配
MemoryLimit(systemd)或memory.limit_in_bytes(cgroup v1),硬隔离内存上限,防止一个进程吃光所有内存 - 用
earlyoom替代默认 OOM Killer:它更早介入(比如available 时就预警并杀进程),留出缓冲窗口,且支持自定义 kill 逻辑 - Java 应用务必设
-Xmx,且不超过容器或 cgroup 内存 limit 的 75%,避免 JVM 自身内存管理(metaspace、off-heap)突破边界 - 定期检查
/proc/*/status中的MMUPageSize和MMUPageSize,大页(HugePages)未启用时,小页 TLB miss 高会加剧内存碎片,间接抬高 oom_score
最常被忽略的一点:OOM Killer 的评分依据是 anon-rss + file-rss + shmem-rss,但很多数据库(如 MySQL 的 buffer pool)用的是 mmap(MAP_ANONYMOUS),这部分算进 anon-rss;而某些语言 runtime(如 Go 的 heap)会主动 madvise(MADV_DONTNEED) 归还内存,导致 RSS 波动剧烈——这时看 oom_score 比看 top %MEM 更准,但比看 /sys/fs/cgroup/memory/memory.usage_in_bytes 更滞后。


















