R multicore mcfork(): невозможно использовать fork: невозможно выделить память

Я получаю титульную ошибку:

mcfork(): Unable to fork: Cannot allocate memory

после попытки запуска функции с mcapply, но top говорит, что я на 51%

Это экземпляр EC2, но у меня есть современный R.

Кто-нибудь знает, что еще может вызвать эту ошибку?

Спасибо,

-N

Ответ 1

Проблема может быть именно тем, что предлагает сообщение об ошибке: недостаточно памяти для вилки и создания параллельных процессов.

R по существу необходимо создать копию всего, что в памяти для каждого отдельного процесса (насколько мне известно, он не использует разделяемую память). Если вы уже используете 51% своей ОЗУ с одним процессом, то у вас недостаточно памяти для создания второго процесса, поскольку для этого потребуется 102% всей вашей оперативной памяти.

Try:

  • Использование меньшего количества ядер. Если вы пытались использовать 4 ядра, возможно, у вас достаточно ОЗУ для поддержки 3 параллельных потоков, но не 4. registerDoMC(2), например, установит номер параллельных потоков до 2 (если вы используете параллельный бэкэнд doMC).
  • Используя меньше памяти - не видя остальной части вашего кода, трудно предложить способы этого. Одна вещь, которая может помочь, - выяснить, какие объекты R занимают всю память (Определение использования памяти объектами?), а затем удалять любые объекты из памяти, t need (rm(my_big_object))
  • Добавление большего количества оперативной памяти - если все остальное не работает, бросьте на него оборудование, чтобы у вас было больше возможностей.
  • Привязка к одиночной потоковой передаче - многопоточная обработка в R - это компромисс между процессором и памятью. Похоже, в этом случае у вас может не хватить памяти для поддержки мощности процессора, поэтому лучший способ действий - просто придерживаться одного ядра.

Ответ 2

Функция R mcfork является только оболочкой для syscall fork (BtW, на странице руководства говорит, что этот вызов сам по себе обертка к clone)

Я создал простую программу на С++ для тестирования поведения 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;
}

Во-первых, программа выделяет около 8 ГБ данных в кучу. Затем он генерирует 2 ^ 2 ^ 2 = 8 детей через вызов fork и ждет, чтобы быть убитым пользователем, и вводит бесконечный цикл, который легко обнаружить в диспетчере задач.

Вот мои наблюдения:

  • Для успеха fork у вас должно быть не менее 51% свободной памяти в моей системе, но этот включает swap. Вы можете изменить это, отредактировав файлы /proc/sys/vm/overcommit_* proc.
  • Как и ожидалось, ни один из детей не получает больше памяти, поэтому эта свободная память на 51% остается свободной на протяжении всей программы, и все последующие вилки также не терпят неудачу.
  • Память разделяется между вилками, поэтому она восстанавливается только после того, как вы убили последнего ребенка.

Проблема фрагментации памяти

Вы не должны беспокоиться о каком-либо слое фрагментации памяти в отношении fork. Фрагментация R-памяти здесь не применяется, поскольку fork работает в виртуальной памяти. Вы не должны беспокоиться о фрагментации физической памяти, поскольку практически все современные операционные системы используют виртуальную память (что, следовательно, позволяет использовать swap). Единственной фрагментацией памяти, которая может возникнуть, является фрагментация пространства виртуальной памяти, но пространство виртуальной памяти AFAIK на Linux составляет 2 ^ 47, что является более чем огромным, и на протяжении многих десятилетий у вас не должно быть проблем с поиском непрерывных областей любой практический размер.

Резюме:

Удостоверьтесь, что у вас больше свопинга, чем в физической памяти, и пока ваши вычисления на самом деле не нуждаются в большем объеме памяти, тогда у вас есть в ОЗУ, вы можете mcfork их столько, сколько хотите.

Или, если вы готовы рискнуть стабильности (голода в памяти) всей системы, попробуйте echo 1 >/proc/sys/vm/overcommit_memory как root на linux.

Или еще лучше: (более безопасно)

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

У меня была такая же ошибка, при использовании каретки для обучения модели rpart в системе с 64 ГБ памяти, с параллельной обработкой с использованием 6 ядер на 7-ядерном компьютере. Изменено до 5 ядро, и проблема решена.

library(doMC)
registerDoMC(5)

Ответ 4

Я столкнулся с подобной проблемой прямо сейчас. Я не буду утверждать, что знаю правильный ответ. Оба вышеупомянутых ответа предлагают способы действий, которые могут работать, особенно если ваши вилки создают дополнительные требования к записи в память одновременно. Тем не менее, я думал, что что-то еще может быть источником трудности. фрагментация памяти. См. 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 к смежным блокам ОЗУ. Также за ?Memory-limits требование должно быть о адресном пространстве, а не о RAM, поэтому это может быть неверно (например, на 64-битной машине) YMMV.

Ответ 5

Заметка для тех, кто хочет использовать графический интерфейс, например RStudio.
Если вы хотите воспользоваться параллельной обработкой, рекомендуется не использовать графический интерфейс, поскольку это прерывает многопоточные процессы между вашим кодом и программой GUI. Вот выдержка из справочной системы пакета registerDoMC по R:

Многоядерная функциональность, первоначально написанная Саймоном Урбанеком и включенная в параллельный пакет в R 2.14.0, предоставляет функции для параллельного выполнения R-кода на машинах с несколькими ядрами или процессорами, используя системный вызов fork для создания копий текущий процесс.

Многоуровневая функциональность и, следовательно, registerDoMC, не должны использоваться в среде GUI, поскольку несколько процессов затем используют один и тот же графический интерфейс.

Я решил аналогичную ошибку, испытываемую OP, отключив registerDoMC(cores = n) при запуске моей программы с помощью RStudio. Многопроцессорная работа лучше всего работает с базой R. Надеюсь, это поможет.