根本原因是vm.overcommit_memory=0导致内核在fork前强制校验内存预留,而非物理内存不足;必须设为1并同步禁用透明大页(THP),否则COW开销激增、mem_fragmentation_ratio>1.5、RSS异常飙升。

为什么Redis日志总报“Cannot allocate memory”却free显示内存充足
根本原因不是物理内存真不够,而是vm.overcommit_memory=0(Linux默认值)让内核在fork前做了一次“纸面检查”:它假定子进程会复制父进程全部匿名页(哪怕实际只读),于是要求预留等量物理内存。Redis的bgsave或bgrewriteaof触发fork时,这个检查常失败,直接返回Cannot allocate memory错误。
此时redis-cli info memory里used_memory_rss可能突然翻倍,但used_memory几乎不变——这正是COW机制被阻断、内核被迫提前分配的典型痕迹。
必须设为1,但不能只设1
vm.overcommit_memory = 1是唯一能绕过上述检查、让COW真正起效的取值。设为2会引入overcommit_ratio硬上限,在Redis高内存碎片场景下反而更容易触发OOM killer。
- 临时生效:
echo 1 > /proc/sys/vm/overcommit_memory - 永久生效:在
/etc/sysctl.conf中追加vm.overcommit_memory = 1,再执行sysctl -p - 绝对不要只改这一项——单独启用
vm.overcommit_memory = 1后,若系统仍开启透明大页(THP),khugepaged会持续合并Redis的匿名页,导致COW开销激增,mem_fragmentation_ratio飙升至>1.5,RSS比预期高30%–50%
必须同步禁用透明大页(THP)
Redis内存访问高度随机,THP不仅无益,还会破坏COW效率。确认是否启用:
cat /sys/kernel/mm/transparent_hugepage/enabled输出含[always]或[madvise]即为启用;cat /sys/kernel/mm/transparent_hugepage/defrag非never也会干扰。
立即禁用:
echo never > /sys/kernel/mm/transparent_hugepage/enabled
并加入开机脚本(如/etc/rc.local),否则重启后失效。
配套观察指标与兜底措施
调完参数不等于万事大吉。必须持续盯住两个关键指标:
-
mem_fragmentation_ratio:应≤1.5。持续高于此值说明内存碎片严重,COW压力仍在,需检查是否有长期未释放的大对象或频繁resize的集合 -
used_memory_rss / used_memory比值:稳定在1.0–1.3之间属正常;若长期>1.5,即使vm.overcommit_memory=1且THP已关,也要怀疑是否存在内存泄漏或客户端异常写入模式
另外,maxmemory建议预留20%–30%系统内存给OS和Redis自身开销,避免极端情况下fork失败后连日志都写不出。


















