9

父进程在尝试 fork 子进程时失败并显示 errno=12(Out of memory)。父进程在 Linux 3.0 内核 - SLES 11 上运行。在分叉子进程时,父进程已经使用了大约 70% 的 RAM(180GB/256GB)。这个问题有什么解决方法吗?

该应用程序是用 C++ 编写的,使用 g++ 4.6.3 编译。

4

3 回答 3

12

也许在您的系统中防止了虚拟内存过度提交。

如果被阻止,则虚拟内存不能大于物理 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 中的过度使用内存

于 2013-03-25T19:33:45.693 回答
1

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 编程了解更多信息。

PS。

如果您fork只是为了gdb显示回溯,请考虑更简单的替代方案,例如最近的 GCC 的 libbacktraceWolf 的 libbacktrace ...

于 2013-03-25T06:20:48.420 回答
0

Linux 上一个更好的解决方案是使用 vfork 或 posix_spawn (因为它会尝试使用 vfork 如果可能): vfork “创建新进程而不复制父进程的页表”,因此即使您的应用程序使用更多超过 50% 的可用 RAM。

请注意,std::system 和 QProcess::execute 也在后台使用 fork,在 Qt 框架中甚至有一张关于这个问题的票:https ://bugreports.qt.io/browse/QTBUG-17331

于 2020-02-17T16:45:50.380 回答