R multicore mcfork():无法分叉:无法分配内存

时间:2013-03-27 20:35:22

标签: r memory amazon-ec2 multicore domc

我收到了名义错误:

mcfork(): Unable to fork: Cannot allocate memory
尝试使用mcapply运行函数后

,但top说我是51%

这是在EC2实例上,但我确实有最新的R.

有谁知道还有什么可能导致此错误?

谢谢,

-N

5 个答案:

答案 0 :(得分:15)

问题可能正是错误消息所暗示的:没有足够的内存来分叉和创建并行进程。

R本质上需要为每个单独的进程创建内存中的所有内容的副本(据我所知,它不使用共享内存)。如果您已经在一个进程中使用了51%的RAM,那么您没有足够的内存来创建第二个进程,因为这将需要102%的RAM。

尝试:

  1. 使用更少的内核 - 如果您尝试使用4个内核,则可能有足够的RAM来支持3个并行线程,但不是4个。registerDoMC(2)例如,将设置并行线程数为2(如果使用doMC并行后端)。
  2. 使用更少的内存 - 在没有看到其余代码的情况下,很难建议实现此目的的方法。可能有帮助的一件事是确定哪些R对象占用了所有内存(Determining memory usage of objects?),然后从内存中删除了不需要的任何对象(rm(my_big_object)
  3. 添加更多内存 - 如果所有其他方法都失败了,请向其投放硬件,以便您拥有更多容量。
  4. 坚持单线程 - R中的多线程处理是CPU和内存的权衡。听起来在这种情况下,您可能没有足够的内存来支持您拥有的CPU能力,因此最好的做法可能就是坚持使用单个核心。

答案 1 :(得分:5)

R函数mcfork只是系统调用fork的包装器(BtW,手册页说,这个调用本身就是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个子节点并等待被用户杀死,并进入无限循环以便在任务管理器上找到。

以下是我的观察:

  1. 要使fork成功,您需要在我的系统上至少有51%的可用内存,但包括交换。您可以通过编辑/proc/sys/vm/overcommit_* proc文件来更改此内容。
  2. 正如预期的那样,没有一个孩子占用更多内存,因此这个51%的可用内存在整个程序过程中仍然是免费的,并且所有后续分叉也不会失败。
  3. 内存在分叉之间共享,因此只有在您杀死最后一个孩子后才会回收。
  4. 内存碎片问题

    您不应该担心与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

答案 2 :(得分:1)

我有同样的错误,同时使用插入符号在64 GB内存的系统上训练rpart模型,并在7核心机器上使用6核进行并行处理。改为5核心,问题就出现了。

library(doMC)
registerDoMC(5)

答案 3 :(得分:1)

我现在遇到了类似的问题。我不会声称知道正确的答案。上述两个答案都提出了可能有效的行动方案,特别是如果您的叉子同时对内存产生额外的写入要求。但是,我一直认为其他东西可能是困难的根源。内存碎片。请参阅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每个WHERE p.parent_id IS NOT NULL的要求应该是地址空间而不是RAM本身 - 所以这可能是不正确的(特别是在64位机器上)YMMV。

答案 4 :(得分:1)

想要使用RStudio等GUI的人的注意事项。
如果要利用并行处理,建议不要使用GUI,因为它会中断代码和GUI程序之间的多线程进程。以下是关于R的<{1}}包帮助手册的摘录

  

多核功能最初由Simon Urbanek编写并包含在R 2.14.0中的并行包中,它提供了在具有多个内核或处理器的机器上并行执行R代码的功能,使用系统fork调用来生成副本目前的过程。

     

多核功能以及寄存器DoMC不应在GUI环境中使用,因为多个进程共享同一个GUI。

我在使用RStudio运行我的程序时通过禁用registerDoMC解决了OP遇到的类似错误。多处理最适合基础R.希望这会有所帮助。