一台 16 核 32G 的 CentOS 7 启动 Redis 时报 Cannot allocate memory,free 显示还有十几 G 空闲,同一台机器上其他服务都正常。

原因不止一个,得分开看。vm.overcommit_memory 被设成 2,内核按 CommitLimit 严格核算,预留的地址空间也会被算进去;Redis 的 fork 需要与原进程等量的虚拟内存,严格模式下直接拒绝;CommitLimit 受 overcommit_ratio 影响,实际可用提交量远小于物理内存;进程里有大量 mmap 预留,虚拟内存统计已经把额度占满。

动手时先确认严格模式与当前提交量

sysctl vm.overcommit_memory && grep -E 'CommitLimit|Committed_AS' /proc/meminfo

接着按业务需要调整严格模式下的比例

sysctl -w vm.overcommit_ratio=80

或改回启发式策略并说明风险

sysctl -w vm.overcommit_memory=0

末了重新拉起服务并观察是否还报错

systemctl restart redis && journalctl -u redis -n 20 --no-pager

当时还开着另一个排查窗口,两边日志对照着看才定位到。

恢复的判定其实很直接。Redis 正常启动并监听端口,/proc/meminfo 里 Committed_AS 低于 CommitLimit,日志中不再出现 Cannot allocate memory。

容易忽略的是,严格模式适合内存必须可控的场景,改成 0 之后就靠内核估算,超卖过多会直接触发 OOM;改之前先把 swap 和 cgroup 上限一起算清。拖得越久,排查成本越高,因为现场状态会被后续操作覆盖。

作者 9823189