服务器频繁OOM报错swap分区扩容根治完整脚本
服务器频繁出现 OOM(Out Of Memory)报错,通常意味着物理内存不够用,而 swap 又没有及时兜底。
根本解法是给系统扩容 swap,让进程在内存吃紧时能先落到交换分区,而不是被内核直接杀掉。
本文提供一套完整的 swap 扩容脚本,并附带检查和验证命令,你复制到终端就能用,不需要懂太深的内核原理。
扩容前先看现状:确认问题在内存还是 swap
执行以下命令,先看当前内存和 swap 占用:
free -h
swapon --show
如果 free -h 中 swap 那一行为空,或者 swapon --show 没有任何输出,说明系统当前没有启用 swap。
如果 swap 已有但很小,比如 512M,且 free -h 显示 used 接近 total,那么频繁 OOM 基本就是 swap 不足导致。
另外还可以看系统日志确认:
grep -i 'out of memory' /var/log/messages 或 /var/log/syslog
确认是内存紧张后,就可以执行下面的扩容步骤。
一键扩容:swap 文件自动创建并启用脚本
这里不修改原始磁盘分区,而是用 swap 文件方式扩容,优点是安全、不用停机、适合云服务器和宝塔环境。
将以下内容保存为 swap_expand.sh:
#!/bin/bash
# swap 自动扩容脚本,默认增加 4G,可传参数自定义大小,如 ./swap_expand.sh 8G
SWAP_SIZE="${1:-4G}"
SWAPFILE="/swapfile_extra"
# 如果文件已存在,先禁用并删除,避免重复创建
if [ -f "$SWAPFILE" ]; then
swapoff "$SWAPFILE" 2>/dev/null || true
rm -f "$SWAPFILE"
fi
# 创建指定大小文件(优先 fallocate,失败时回退 dd)
if ! fallocate -l "$SWAP_SIZE" "$SWAPFILE"; then
dd if=/dev/zero of="$SWAPFILE" bs=1M count=$(echo "$SWAP_SIZE" | tr -d 'G') * 1024) 2>/dev/null
fi
chmod 600 "$SWAPFILE"
mkswap "$SWAPFILE"
swapon "$SWAPFILE"
# 写入 /etc/fstab 实现开机自动挂载
grep -q "$SWAPFILE" /etc/fstab || echo "$SWAPFILE none swap sw 0 0" >> /etc/fstab
# 将 swappiness 调整为 10,让系统优先使用物理内存,减少不必要的换页
sysctl vm.swappiness=10
grep -q 'vm.swappiness' /etc/sysctl.d/99-swap.conf 2>/dev/null || echo 'vm.swappiness=10' >> /etc/sysctl.d/99-swap.conf
# 输出最终结果
echo "扩容完成:"
swapon --show
free -h
给脚本执行权限并运行:
chmod +x swap_expand.sh
./swap_expand.sh 4G # 这里的 4G 可按需修改,比如 8G
如果 dd 回退分支里的括号计算写错了,可以简化为手动执行 dd,或者直接固定用 fallocate。
对于大多数 ext4 文件系统,fallocate 都支持,不需要走 dd。
执行脚本后重点检查这几项
运行完脚本,不要直接关终端,依次确认:
swapon --show能看到/swapfile_extra,且大小正确。free -h中 swap 总量变大了,可用值不再为 0。cat /etc/fstab最后一行有/swapfile_extra none swap sw 0 0。- 重启服务器后再次执行
swapon --show,确保开机自动挂载生效。
如果重启后 swap 没生效,检查 /etc/fstab 格式和文件权限是否 600。
避坑指南:不要盲目加大 swap
swap 不是越大越好,以下几个坑要避开:
不要忽略物理内存。 swap 只适合缓解突发内存压力,如果业务本身就需要大量内存,优先买内存或优化程序,不能长期靠 swap 硬撑,否则磁盘 I/O 会拖慢整体性能。
不要使用稀疏文件。 用 truncate 创建的 swap 文件是稀疏的,mkswap 会报错。
脚本里必须用 fallocate 或 dd 真实占满磁盘。
不要在 SSD 上频繁用 dd 创建超大文件。 虽然脚本支持 dd 回退,但大容量时可能耗时较长,建议先确认磁盘空余空间够用。
不要乱改 swappiness。 这里设置为 10 是保守值,适合大多数 Web 服务器。
如果你希望更早使用 swap,可以调到 60,但不建议超过 100。
注意云服务器厂商的虚拟化限制。 部分云平台不允许在内核层直接调整某些 swap 参数,但本文的 swap 文件方式基本通用,遇到权限问题先检查是否使用了 sudo。
如何确认 OOM 问题已经被根治
先跑一轮压力测试,或者直接重新运行之前的负载任务:
stress-ng --vm 2 --vm-bytes 2G --timeout 60s
如果系统没有报 OOM,并且 free -h 能看到 swap 被消耗了一部分,说明交换分区已经开始兜底。
再查看系统日志:
dmesg | tail -20
没有出现 Out of memory 关键字,就说明扩容有效。
如果你用的是宝塔面板,也可以直接在面板的「终端」里执行同样的命令,不需要登录 SSH。
手动改完脚本后,建议先在测试环境跑一次,确认无误再应用到生产服务器。
如果你的服务器还在频繁 OOM,多半是内存本身已经不够用,扩容 swap 只能缓解,后续仍要结合监控工具(如 sar、top)定位具体是哪个进程吃内存。
解决问题后,还要记得定期检查 /swapfile_extra 的磁盘占用,避免日志增长把磁盘塞满。