Linux系统明明还有足够的物理内存,调用fork却返回ENOMEM

使用systemtab hook fork,定位到报错调用路径SYSCALL_DEFINE0(fork)-》kernel_clone-》copy_process-》copy_mm-》dup_mm-》dup_mmap-》security_vm_enough_memory_mm-》__vm_enough_memory

__vm_enough_memory返回了 -ENOMEM。其源码如下:

从代码可知fork需要拷贝父进程的虚拟空间给子进程,父进程是一个使用了巨大虚拟内存的进程。overcommit机制策略影响虚拟内存分配,默认策略是0,即剩余系统物理内存+swap<当前要分配的虚拟内存,就返回失败。

解决方案,将overcommit策略设置为1,即overcommit_always.

overcommit 机制介绍:
linux memory overcommit策略一共分为三种(可以通过/proc/sys/vm/overcommit_memory修改策略):

参考linux kernel document:overcommit-accounting

参考内核mm/util.c __vm_enough_memory()

(1)启发式策略(overcommit_memory==0):

如果有足够可用的物理内存供使用,则内存分配成功,否则失败.

可用物理内存可以通过对/proc/meminfo的统计信息做一下计算得到:"free + buffer + cached - shm + swap + slab_recalimable - zone_total_reserved(各zone预留内存总和,一般是固定的)"

__vm_enough_memory通过比较请求的内存数量与当前可用的物理内存来决定是否允许请求。

(2)允许过度使用策略(overcommit_memory==1):

无论分配多少内存都会成功,这样的好处是可以使用所有的物理内存,但是有可能引发oom。(为了验证你可以动手试一下,譬如当前有50M可用的物理内存,malloc即使100M也是成功返回的,但是写这段内存的时候,超过50M就是oom)

(3)不允许过度使用策略(overcommit_memory==2):

系统的所有虚拟内存加起来不得超过 “总物理内存 + CommitLimt”(CommitLimt=总物理内存*overcommit_ratio%)。overcommit_ratio可以在/proc/sys/vm里设定,默认是50,也就是CommitLimt默认是0.5倍的总物理内存。当前所有进程一共使用的虚拟内存Committed_AS和CommitLimt可通过/proc/meminfo查看。(为了验证你也可以试一下,看一下当你的Committed_AS超过“总物理内存 + CommitLimt”时,这时候你在终端上敲个命令就会提示你fork:alloc memory fail)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

无v邪

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值