首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >R多核mcfork():无法派生:无法分配内存

R多核mcfork():无法派生:无法分配内存
EN

Stack Overflow用户
提问于 2013-03-28 04:35:22
回答 5查看 13.3K关注 0票数 21

我得到了标题错误:

代码语言:javascript
运行
复制
mcfork(): Unable to fork: Cannot allocate memory

在尝试使用mcapply运行函数后,但top说我使用了51%

这是在一个EC2实例上,但我有最新的R。

还有没有人知道导致这个错误的其他原因?

谢谢,

-N

EN

回答 5

Stack Overflow用户

回答已采纳

发布于 2015-08-24 05:45:19

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

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

尝试:

  1. Using number cores -如果你尝试使用4个内核,你可能有足够的内存来支持3个并行线程,但不能支持4个。例如,registerDoMC(2)会将并行线程的数量设置为2(如果你正在使用doMC并行后端)。
  2. Using less memory -在看不到其余代码的情况下,很难提出实现这一目标的方法。有一件事可能会有帮助,那就是找出哪些R对象占用了所有的内存(Determining memory usage of objects?),然后从内存中删除任何你不需要的对象,如果其他方法都失败了,就扔硬件给它,这样你就有更多的capacity.
  3. Sticking到单线程了-R中的多线程处理是对和内存的权衡。听起来,在这种情况下,你可能没有足够的内存来支持你所拥有的CPU能力,所以最好的做法可能是只使用一个内核。
票数 17
EN

Stack Overflow用户

发布于 2016-05-20 17:35:32

R函数mcfork只是syscall fork的包装器(BtW,手册页上说,此调用本身就是clone的包装器)

我创建了一个简单的C++程序来测试fork的行为:

代码语言:javascript
运行
复制
#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;
}

首先,程序在堆上分配大约8 8GB的数据。然后,它通过fork调用产生2^2^2 =8个子进程,等待用户终止,并进入一个无限循环,以便在任务管理器上容易发现。

以下是我的观察结果:

  1. 为了使分支成功,您需要在我的系统上至少有51%的空闲内存,但此包含交换。你可以通过编辑/proc/sys/vm/overcommit_* proc文件来改变这一点。
  2. 正如预期的那样,没有一个子进程占用更多的内存,所以这51%的空闲内存在整个程序过程中都是空闲的,并且所有后续的分支也不会失败。
  3. 内存是在fork之间共享的,所以只有在你杀死最后一个孩子之后,它才会被回收。

内存碎片问题

您不应该担心关于fork的任何一层内存碎片。R的内存碎片在这里不适用,因为fork在虚拟内存上操作。您不必担心物理内存的碎片,因为几乎所有现代操作系统都使用虚拟内存(这使得它们能够使用交换)。唯一有问题的内存碎片是虚拟内存空间的碎片,但是Linux虚拟内存空间上的AFAIK是2^47,这是非常巨大的,几十年来,您应该不会遇到任何实际大小的连续区域的问题。

摘要:

确保你有比物理内存更多的交换内存,并且只要你的计算实际上不需要比你在内存中更多的内存,你就可以根据你的需要来mcfork它们。

或者,如果您愿意冒整个系统的稳定性(内存匮乏)的风险,可以尝试在linux上以根用户身份使用echo 1 >/proc/sys/vm/overcommit_memory

或者更好:(更安全)

代码语言:javascript
运行
复制
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

票数 5
EN

Stack Overflow用户

发布于 2016-11-30 16:39:34

给那些想要使用图形用户界面的人的注意事项,比如RStudio。

如果你想利用并行处理,建议不要使用GUI,因为它会中断你的代码和GUI程序之间的多线程进程。以下是关于R的registerDoMC包帮助手册的摘录:

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

在图形用户界面环境中不应该使用多核功能,因此也不应该使用registerDoMC,因为多个进程会共享相同的图形用户界面。

我通过在使用RStudio运行我的程序时禁用registerDoMC(cores = n),解决了OP遇到的类似错误。多处理在基数R上工作得最好。希望这对你有所帮助。

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/15668893

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档