Linux OOM 不是内存小,90% 的人都理解错了
为什么你的服务器总是 OOM?别急着买内存条
很多站长和运维同学一看到服务器出现 OOM(Out of Memory)就认为内存不够用,赶紧升级配置。
其实,90% 的 OOM 不是物理内存太小,而是内核的内存分配策略或进程资源限制出了问题。
今天我们就从零开始,一步步搞清楚 OOM 的真相,并找出对应的解决方法。
认识 OOM 的两大元凶
OOM 的全称是 Out of Memory,但 Linux 内核并不是等到物理内存真正用光才触发。
在以下两种情况下,OOM Killer(内存溢出杀手)会强制杀掉进程:
- 过度分配(Overcommit):Linux 默认允许进程申请比实际物理内存 + 交换空间更多的内存(这叫 overcommit)。大部分进程不会把申请的内存全用掉,但一旦所有进程同时大量写入,内存瞬间撑爆,内核只好启动 OOM Killer。
- cgroup 内存限制:在使用容器(如 Docker)或 systemd 服务时,如果设置了 MemoryLimit,即使物理内存还有剩余,进程也会被 OOM Kill。
所以,OOM 不等于物理内存小,理解这一点才能对症下药。
第一步:确认当前是否被 OOM 误杀
在动手调整前,先确认最近有没有 OOM 事件以及原因。
# 查看系统日志中的 OOM 记录
dmesg | grep -i oom
# 或者查看内核日志文件
sudo grep -i oom /var/log/kern.log
输出类似:
[123456.789] oom-kill:constraint=CONSTRAINT_NONE...
[123456.789] Memory cgroup out of memory: Killed process 12345 (nginx)
第二行如果提到 Memory cgroup,说明是 cgroup 限制导致的,与物理内存大小无关。
第二步:检查内存分配策略和 swap 配置
查看当前 overcommit 设置
sysctl vm.overcommit_memory
0– 默认,内核根据当前空闲内存估算是否允许 overcommit(启发式)。1– 总是允许 overcommit(可能更容易触发 OOM)。2– 禁止超过某个比例(vm.overcommit_ratio控制)的 overcommit,最保守。
大多数 OOM 问题的原因是 默认(0) 过于乐观。
可以临时改成 2 试试效果:
sudo sysctl -w vm.overcommit_memory=2
sudo sysctl -w vm.overcommit_ratio=50 # 最多允许物理内存+swap的50%
检查 swap 是否太小
如果没有 swap 或 swap 很小,内存紧张时内核无法回收内存,OOM 更容易发生。
free -h | grep -i swap
如果 Swap 总行为 0,建议添加 swap 文件(参考下方避坑部分)。
第三步:调整配置,从根源减少 OOM
方案 A:修改 sysctl 参数持久化
用编辑器打开 /etc/sysctl.conf,添加或修改以下内容:
vm.overcommit_memory = 2
vm.overcommit_ratio = 50
vm.swappiness = 10
然后执行 sudo sysctl -p 生效。swappiness 控制内核使用交换空间的倾向,值越低越优先使用物理内存,可以减少 OOM Killer 的触发。
方案 B:为特定进程设置 OOM 保护
如果某个服务(如 MySQL)经常被杀,可以给它设置更高的 oom_score_adj,让内核优先杀其他进程:
# 找到进程 PID
ps aux | grep mysqld
# 设置 oom_score_adj(取值范围 -1000 到 1000,越小越不容易被杀)
sudo echo -500 > /proc/[PID]/oom_score_adj
方案 C:检查并调整 cgroup 限制
如果是容器或 systemd 服务:
# 查看 systemd 服务的 MemoryLimit
systemctl show nginx.service | grep MemoryLimit
# 临时调整(单位字节)
sudo systemctl set-property nginx.service MemoryLimit=512M
避坑指南:这几点90%的人想错了
- 不要一上来就加内存。先查看
dmesg日志,如果出现constraint=CONSTRAINT_MEMCG,加了物理内存也解决不了,因为 cgroup 限制没解除。 - swap 一定要有,哪怕只有1GB。没有 swap 的服务器 OOM 概率会高很多。添加 swap 文件:
sudo fallocate -l 2G /swapfile
sudo chmod 600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile
# 永久挂载:在 /etc/fstab 中添加一行
- 别盲目调高
vm.overcommit_ratio到 100,那等于关闭保护,会让系统更不稳定。
效果验证:如何确认问题已解决
调整后,进行压力测试来模拟高内存场景:
# 使用 stress 工具(先安装:sudo apt install stress 或 yum install stress)
stress --vm 4 --vm-bytes 512M --timeout 30s
观察是否还会触发 OOM:
dmesg | tail -5 # 如果没有新的 oom-kill 信息,说明配置有效
free -h # 确认内存使用率变化
也可以观察 /var/log/syslog 或 /var/log/messages。
如果连续一周没有 OOM 事件,说明调整正确。
总结
遇到 OOM 别第一时间买内存条。
按照本文步骤检查 overcommit、swap 和 cgroup 配置,通常能解决大部分问题。
记住,Linux OOM 不是内存小,90% 的人都理解错了这句话背后的核心是内存管理策略。
如果你按照上述方法操作后仍有疑问,建议在调整前先完整备份关键配置,并在测试环境验证再上线。