malloc返回NULL说明内核拒绝分配请求,常见原因包括触达RLIMIT_AS、OOM killer前的保守拒绝或vm.overcommit_memory=2时预估物理内存不足。

malloc 返回 NULL 说明什么
当 malloc 返回 NULL,不是“内存彻底用光了”,而是内核拒绝了这次分配请求。常见原因包括:进程触达 RLIMIT_AS(虚拟内存上限)、触发 OOM killer 前的保守拒绝、或 vm.overcommit_memory=2 下预估物理内存不足。
注意:malloc 成功返回指针 ≠ 对应内存已实际映射到物理页——Linux 默认启用 lazy allocation,真正缺页时才调 do_page_fault。所以 malloc 成功后首次写入仍可能 SIGSEGV(如被 OOM killer 杀掉或 MAP_NORESERVE 未设)。
为什么 free 后 malloc 还失败
堆碎片是主因。glibc 的 ptmalloc 将空闲 chunk 按大小挂入 bins,但大块内存释放后若周围被占用,无法合并成连续区域,导致后续大尺寸 malloc 找不到足够连续虚拟地址空间。
可检查:/proc/ 看堆段是否零散;用 mallinfo() 或 malloc_stats() 观察 ordblks(空闲块数)和 smblks(小块数)是否异常高。
- 避免频繁 malloc/free 大小不一的内存,改用内存池或
mmap(MAP_ANONYMOUS)管理大块 -
mallopt(M_MMAP_THRESHOLD, 128*1024)可让超过阈值的分配直走mmap,绕过堆碎片
OOM killer 是怎么选中进程的
内核在 out_of_memory() 中遍历所有进程,计算 oom_score:基于 RSS、swap usage、oom_score_adj(范围 -1000~1000),值越高越容易被杀。root 进程默认不为 0,但 oom_score_adj = -1000 可彻底豁免。
关键点:
-
/proc/显示当前得分(只读),/oom_score /proc/可写入调整/oom_score_adj - 容器环境需注意:cgroup v1 的
memory.oom_control或 cgroup v2 的memory.oom.group会影响判定粒度 - 即使没被 kill,
pagefault延迟激增、pgmajfault上升也是 OOM 前兆,可通过vmstat 1监测
如何判断是 overcommit 导致的失败
查 /proc/sys/vm/overcommit_memory:0(启发式)、1(总是允许)、2(严格检查)。若为 2,再看 /proc/meminfo 中 CommitLimit 和 Committed_AS —— 当后者接近前者时,malloc 就会开始返回 NULL,哪怕 MemFree 还剩很多。
临时缓解:
-
echo 1 > /proc/sys/vm/overcommit_memory(慎用,可能引发 OOM killer) - 调大
vm.overcommit_ratio(仅对 mode 2 生效) - 清理缓存:
echo 1 > /proc/sys/vm/drop_caches(仅释放 pagecache,不影响脏页)
真正稳定的解法是控制应用内存增长节奏,而不是依赖 overcommit 策略兜底——尤其在生产服务中,overcommit=2 加合理 limit 才最可控。










