linux内存分配失败主因是内核页分配受阻,需从内存视图、分配路径、压力源三方面排查:memavailable比free更准;slab过高、directmap异常、anon-hugepages碎片化、cgroup限值、page cache不可回收、swap异常、numa不平衡均可能触发oom或-enomem。

Linux 内存分配失败,通常不是单纯“物理内存不够”,而是内核在尝试分配页(page)时无法满足请求,触发 Out of Memory (OOM) killer 或返回 -ENOMEM 错误。排查需从内存视图、分配路径、压力来源三方面入手,而非只看 free 输出。
看清真实内存使用:别只信 free -h
free -h 显示的 “available” 是估算值,不反映实际可分配能力。关键要看:
-
/proc/meminfo 中的
MemAvailable(较准)、MemFree(裸空闲,常很低)、Buffers/Cached(可回收,但非全部即时可用) -
Slab 使用:
cat /proc/meminfo | grep -i slab,过高(尤其SReclaimable远小于SSlab)说明内核对象(如 dentry/inode)占内存多,可能由大量小文件或 NFS 挂载引发 -
DirectMap 大小:
dmesg | grep "DirectMap",若DirectMap4k占比异常高,说明 page table 膨胀严重(常见于大量进程或 hugepage 配置不当)
定位谁在吃内存:不只是 top 的 RSS
RSS(Resident Set Size)会重复计算共享内存(如 libc),且不含 page cache。更准的方式是:
- 查 每个进程的真正内存压力:
ps aux --sort=-%mem | head -10粗筛,再进/proc/PID/status看MMUPageSize、MMUHugePageSize和RssAnon/RssFile分项 - 关注 anon-hugepages:
grep AnonHugePages /proc/*/smaps 2>/dev/null | awk '$2 > 10000 {print $0}',单个进程占用超 10GB 大页可能造成碎片化,导致后续普通页分配失败 - 检查 memory cgroup 限值(若启用):
cat /sys/fs/cgroup/memory/xxx/memory.usage_in_bytes和memory.limit_in_bytes,OOM 可能发生在 cgroup 层而非全局
识别隐性内存杀手:cache、swap、NUMA
以下情况常被忽略,却直接导致分配失败:
-
Page cache 不可回收:NFS/CIFS 挂载 + writeback 延迟,或 ext4 的
delalloc模式积压大量 dirty page,cat /proc/vmstat | grep -E "pgpgin|pgpgout|pgmajfault"持续高 pgmajfault 表明缺页频繁,cache 回收滞后 -
Swap 使用异常:swapoff 后仍有
SwapCached高,说明 page reclaim 未清理 swap cache;swapon --show查 swap 分区是否满,/proc/swaps看优先级是否错配导致部分 swap 未启用 -
NUMA 不平衡:
numastat -p PID查进程跨 NUMA node 分配;cat /sys/devices/system/node/node*/meminfo看各 node 的MemFree是否严重不均——即使总内存充足,某 node 耗尽也会触发本地分配失败
快速验证与缓解手段
无需重启即可初步判断和缓解:
- 手动触发内存回收:
echo 1 > /proc/sys/vm/drop_caches(仅释放 page cache,安全);echo 2 > /proc/sys/vm/drop_caches(加 dentries/inodes,慎用) - 临时调优回收策略:
echo 20 > /proc/sys/vm/vfs_cache_pressure(降低 inode/dentry 回收门槛);echo 80 > /proc/sys/vm/swappiness(倾向 swap 而非 OOM,适用于有足够 swap 的场景) - 抓取 OOM 日志:
dmesg -T | grep -i "killed process",确认被杀进程及当时MemAvailable值;结合/var/log/kern.log查完整上下文











