一,问题引入:进程莫名消失,没有日志
你有没有经历过这样的场景:线上服务半夜报警,进程不见了,但 dmesg 里只有一条 "Out of Memory: Killed process" 的记录,然后就没有然后了。你第一反应是——我代码是不是有内存泄漏?
但真相往往没那么简单。
二,核心发现:OOM Killer 的"选妃"机制
Linux 的 OOM Killer 并不是简单的"谁用的多杀谁",而是一个相对打分系统。它的核心逻辑是:在所有候选进程中,选择那个 oom_score 最高的进程杀掉。
oom_score 的计算方式很粗暴:
- 进程用的内存越多,分数越高
- 进程运行时间越短,分数越高(因为"来得晚还敢抢内存")
- 但关键在于——这是一个相对概念,不是绝对值
这意味着什么?你的进程用了几百兆,被杀了;旁边另一个进程用了几个G,还在跑。因为那个大进程可能是数据库或者 SSH 这种关键服务,它的 oom_score_adj 被系统设置为负数,优先级更高。
三,实操指南:如何调试和预防
第一步:查看进程的 OOM Score
# 查看所有进程的 oom_score
cat /proc/[pid]/oom_score
# 查看调整值(默认是0,可调整范围 -1000 ~ +1000)
cat /proc/[pid]/oom_score_adj
第二步:找到真正的"凶手"
dmesg | grep -i "out of memory"
dmesg | grep -i "killed process"
系统日志里会记录被杀的进程 ID 和当时的内存状态。
第三步:保护关键进程
# 将关键进程的 oom_score_adj 设为 -1000,基本上不会被杀
echo -1000 > /proc/[pid]/oom_score_adj
# 永久生效需要写入 sysctl 或 cgroup 配置
第四步:设置内存上限(更优雅的方案) 使用 cgroup v2 限制进程内存:
echo "256M" > /sys/fs/cgroup/user.slice/user-1000.slice/memory.max
四,讨论引导
大家在实际生产环境中遇到过 OOM 问题吗?是怎么定位和解决的?欢迎在评论区分享你的"查凶"经历!