父进程在尝试 fork 子进程时失败并显示 errno=12(Out of memory)。父进程在 Linux 3.0 内核 - SLES 11 上运行。在分叉子进程时,父进程已经使用了大约 70% 的 RAM(180GB/256GB)。这个问题有什么解决方法吗?
该应用程序是用 C++ 编写的,使用 g++ 4.6.3 编译。
父进程在尝试 fork 子进程时失败并显示 errno=12(Out of memory)。父进程在 Linux 3.0 内核 - SLES 11 上运行。在分叉子进程时,父进程已经使用了大约 70% 的 RAM(180GB/256GB)。这个问题有什么解决方法吗?
该应用程序是用 C++ 编写的,使用 g++ 4.6.3 编译。
也许在您的系统中防止了虚拟内存过度提交。
如果被阻止,则虚拟内存不能大于物理 RAM + 交换的大小。如果允许,那么虚拟内存可以大于 RAM+swap。
当您的进程分叉时,您的进程(父进程和子进程)将拥有 2*180GB 的虚拟内存(如果没有交换,那就太多了)。
因此,允许通过这种方式过度提交:
echo 1 > /proc/sys/vm/overcommit_memory
如果子进程立即执行,或者在父进程向自己的内存写入过多之前释放分配的内存,它应该会有所帮助。所以,要小心,如果两个进程都继续使用所有内存,内存不足的杀手可能会起作用。
proc(5) 的手册页说:
/proc/sys/vm/overcommit_memory
该文件包含内核虚拟内存记帐模式。值为: 0:启发式过度使用(这是默认设置) 1:总是过度使用,从不检查 2:总是检查,从不过度使用
在模式 0 中,不检查带有 MAP_NORESERVE 的 mmap(2) 调用,并且默认检查非常弱,导致进程“OOM-killed”的风险。在 Linux 2.4 下,任何非零值都意味着模式 1。在模式 2(自 Linux 2.6 起可用)中,系统上的总虚拟地址空间限制为 (SS + RAM*(r/100)),其中 SS 是交换空间,RAM是物理内存的大小,r是文件/proc/sys/vm/overcommit_ratio的内容。
更多信息:SLES 中的过度使用内存
fork
-ing 需要资源,因为它是在写入时复制进程的可写页面。再次阅读fork(2)手册页。
您至少可以提供一个巨大的临时交换文件。您可以(在一些有足够空间的文件系统上)创建一个巨大的$SWAPFILE
文件
dd if=/dev/zero of=$SWAPFILE bs=1M count=256000
mkswap $SWAPFILE
swapon $SWAPFILE
否则,您可以例如以不同的方式设计您的程序,例如mmap
-ing 一些大文件(并munmap
在 fork 之前对其进行mmap
-ing,然后再对其进行 -ing),或者更简单地从程序的开头开始popen
-ed shell,或一个p2open
-ed 或显式地pipe
对它进行 -s (可能多路复用调用 à lapoll
也很有用),然后向它发出命令。
如果我们知道你的程序在做什么,为什么它会消耗这么多内存,以及它为什么和什么是分叉的,也许我们可以提供更多帮助......
阅读高级 Linux 编程了解更多信息。
如果您fork
只是为了gdb
显示回溯,请考虑更简单的替代方案,例如最近的 GCC 的 libbacktrace或Wolf 的 libbacktrace ...
Linux 上一个更好的解决方案是使用 vfork 或 posix_spawn (因为它会尝试使用 vfork 如果可能): vfork “创建新进程而不复制父进程的页表”,因此即使您的应用程序使用更多超过 50% 的可用 RAM。
请注意,std::system 和 QProcess::execute 也在后台使用 fork,在 Qt 框架中甚至有一张关于这个问题的票:https ://bugreports.qt.io/browse/QTBUG-17331