R多核mcfork():无法分叉:无法分配内存
Posted
技术标签:
【中文标题】R多核mcfork():无法分叉:无法分配内存【英文标题】:R multicore mcfork(): Unable to fork: Cannot allocate memory 【发布时间】:2013-03-18 03:02:42 【问题描述】:我收到了名义上的错误:
mcfork(): Unable to fork: Cannot allocate memory
在尝试使用 mcapply 运行函数后,但 top
说我在 51%
这是在 EC2 实例上,但我确实有最新的 R。
有谁知道还有什么可能导致这个错误?
谢谢,
-N
【问题讨论】:
R 需要连续的内存块。您是否重新启动并尝试使用最少的数据重新运行? 我尝试了另一个具有两倍内存的实例,这解决了这个问题......不过我仍然想更好地理解它,所以我会留下这个问题。 【参考方案1】:问题可能正是错误消息所暗示的:没有足够的内存来分叉和创建并行进程。
R 本质上需要为每个单独的进程创建内存中所有内容的副本(据我所知,它不使用共享内存)。如果您已经在单个进程中使用了 51% 的 RAM,那么您没有足够的内存来创建第二个进程,因为这总共需要 102% 的 RAM。
试试:
-
使用更少的内核 - 如果您尝试使用 4 个内核,您可能有足够的 RAM 来支持 3 个并行线程,但不是 4 个。例如,
registerDoMC(2)
将设置并行线程的数量到 2(如果您使用的是 doMC
并行后端)。
使用更少的内存 - 没有看到您的其余代码,很难提出实现此目的的方法。可能有帮助的一件事是找出哪些 R 对象占用了所有内存 (Determining memory usage of objects?),然后从内存中删除任何不需要的对象 (rm(my_big_object)
)
添加更多 RAM - 如果所有其他方法都失败了,请投入硬件以增加容量。
坚持单线程 - R 中的多线程处理是 CPU 和内存的权衡。在这种情况下,您可能没有足够的内存来支持您拥有的 CPU 能力,因此最好的做法可能是坚持使用单个内核。
【讨论】:
也许我在某些方面错了,但我发现您确实可以分叉一个使用 51% RAM 的进程而不使用 102% 的 RAM。这确实(出于我的目的)是分叉的部分原因,可见。 RAM 可以共享,直到一个进程尝试修改它。 更多详情请见unix.stackexchange.com/questions/155017/…。 @Mike。就像 rpierce 一样,我不同意您的说法,即 fork 需要 50% 的备用 RAM。交换就够了。 @Adam - 啊哈,感谢您的构建。看起来它确实利用共享内存和写入时复制。我们可以同意正确的说法是它需要 51% 的备用 RAM + 交换来分叉吗? @MikeMonteiro 在默认的 Ubuntu 安装上 - 是的,但这是可自定义的行为,对于所有其他 Linux 发行版可能并非如此。有关过度使用内存的详细信息,请参阅我自己对这个问题的回答(如下)。【参考方案2】:R 函数 mcfork
只是系统调用 fork
的包装器(顺便说一句,手册页说,这个调用本身就是 clone
的包装器)
我创建了一个简单的 C++ 程序来测试fork
的行为:
#include <stdio.h>
#include <unistd.h>
#include<vector>
int main(int argc, char **argv)
printf("--beginning of program\n");
std::vector<std::vector<int> > l(50000, std::vector<int>(50000, 0));
// while (true)
int counter = 0;
pid_t pid = fork();
pid = fork();
pid = fork();
if (pid == 0)
// child process
int i = 0;
for (; i < 5; ++i)
printf("child process: counter=%d\n", ++counter);
else if (pid > 0)
// parent process
int j = 0;
for (; j < 5; ++j)
printf("parent process: counter=%d\n", ++counter);
else
// fork failed
printf("fork() failed!\n");
return 1;
printf("--end of program--\n");
while (true)
return 0;
首先,程序在堆上分配了大约 8GB 的数据。 然后,它通过 fork 调用产生 2^2^2 = 8 个孩子并等待被用户杀死,然后进入无限循环以便在任务管理器上轻松发现。
以下是我的观察:
-
要使分叉成功,我的系统上至少需要有 51% 的可用内存,但这包括交换。您可以通过编辑
/proc/sys/vm/overcommit_*
proc 文件来更改此设置。
正如预期的那样,没有一个子进程占用更多内存,因此这 51% 的空闲内存在整个程序过程中保持空闲,并且所有后续分叉也不会失败。
内存在分叉之间共享,因此只有在您杀死最后一个孩子后才会回收。
内存碎片问题
您不应该担心任何与 fork 相关的内存碎片层。 R 的内存碎片在这里不适用,因为 fork 是在虚拟内存上操作的。您不必担心物理内存的碎片,因为几乎所有现代操作系统都使用虚拟内存(因此它们可以使用交换)。唯一可能存在问题的内存碎片是虚拟内存空间的碎片,但 Linux 虚拟内存空间上的 AFAIK 是 2^47,这非常大,几十年来,您在寻找连续区域时应该没有任何问题任何实用的尺寸。
总结:
确保您拥有比物理内存更多的交换空间,并且只要您的计算实际上不需要比 RAM 中更多的内存,您可以mcfork
任意数量。
或者,如果您愿意冒整个系统稳定性(内存不足)的风险,请在 linux 上以 root 身份尝试echo 1 >/proc/sys/vm/overcommit_memory
。
或者更好:(更安全)
echo 2 >/proc/sys/vm/overcommit_memory
echo 100 >/proc/sys/vm/overcommit_ratio
您可以在此处阅读有关过度使用的更多信息:https://www.win.tue.nl/~aeb/linux/lk/lk-9.html
【讨论】:
【参考方案3】:给想要使用 RStudio 等 GUI 的用户的注意事项。
如果您想利用并行处理,建议不要使用 GUI,因为这会中断您的代码和 GUI 程序之间的多线程进程。以下是 R 上registerDoMC
软件包帮助手册的摘录:
最初由 Simon Urbanek 编写并包含在 R 2.14.0 中的并行包中的多核功能提供了在具有多个内核或处理器的机器上并行执行 R 代码的功能,使用系统 fork 调用生成当前进程。
多核功能以及 registerDoMC 不应在 GUI 环境中使用,因为多个进程共享同一个 GUI。
在使用 RStudio 运行我的程序时,我通过禁用 registerDoMC(cores = n)
解决了 OP 遇到的类似错误。多处理最适合使用基础 R。希望这会有所帮助。
【讨论】:
这可能与将来发现问题的人有关,但原始 Q 并未指定使用 GUI。您能否在“如果您使用 GUI,那么...”的行中添加第一句话? @N.McA。谢谢。已更新。【参考方案4】:我在使用 caret 在具有 64 GB 内存的系统上训练 rpart 模型时遇到了同样的错误,在 7 核机器上使用 6 核进行并行处理。换成5核,问题就跑了。
library(doMC)
registerDoMC(5)
【讨论】:
【参考方案5】:我现在遇到了类似的问题。我不会声称知道正确答案。上述两个答案都提出了可能有效的行动方案,特别是如果您的分叉同时对内存产生额外的写入需求。然而,我一直在想其他的东西可能是困难的根源,可见。内存碎片。请参阅https://raspberrypi.stackexchange.com/questions/7856/log-says-i-cant-allocate-memory-but-i-have-more-than-half-of-my-memory-free 以讨论类似 Unix 中的用户看到可用内存但由于内存碎片而遇到内存不足错误的情况。这似乎是 R 的罪魁祸首,特别是因为 R 喜欢连续的 RAM 块。同样根据?Memory-limits
,要求应该是关于地址空间而不是 RAM 本身 - 所以这可能是不正确的(尤其是在 64 位机器上)YMMV。
【讨论】:
以上是关于R多核mcfork():无法分叉:无法分配内存的主要内容,如果未能解决你的问题,请参考以下文章
内存分配“错误:无法分配大小为 75.1 Mb 的向量”[重复]