一台 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 上限一起算清。拖得越久,排查成本越高,因为现场状态会被后续操作覆盖。
