先把当时的情况摆出来。CentOS 7.9 的机器内存八 G,业务偶发报 Cannot allocate memory,free 显示还有两 G 可用,dmesg 里能看到 page allocation failure 的警告。

原因不止一个,得分开看。min_free_kbytes 只有几百 K,内核保留的应急内存不够,原子分配直接失败。也可能是内存碎片严重,连续页申请不到,虽然总量还够。

还有一种情况,水位线设得低,kswapd 回收不及时,分配路径被迫直接回收。另外,容器和宿主机共用一块内存,突发申请把余量吃光。

上来先看当前水位和碎片情况

cat /proc/sys/vm/min_free_kbytes && cat /proc/buddyinfo

然后按内存比例把保留值调高

sysctl -w vm.min_free_kbytes=524288

再往下确认水位线是否跟着变化

grep -E 'min|low|high' /proc/zoneinfo | head

等前面都确认过,再写进配置文件并观察一段时间

echo 'vm.min_free_kbytes = 524288' >> /etc/sysctl.d/99-mem.conf && sysctl -p /etc/sysctl.d/99-mem.conf

恢复的判定其实很直接。dmesg 不再出现 page allocation failure,buddyinfo 里高阶块的可用数量上升,业务侧的内存分配错误消失。

这里还有个坑。min_free_kbytes 一般是内存的百分之一到百分之三,调太大反而浪费;如果碎片问题明显,还得配合内存规整参数一起看。改动前把原配置备份一份,出问题能马上回滚,这比任何技巧都实用。

作者 9823189