Утечка памяти при использовании OpenMP - PullRequest
5 голосов
/ 02 декабря 2010

В приведенном ниже тесте не хватает памяти на 32-битных компьютерах (бросая std :: bad_alloc) в цикле, следующем за сообщением «post MT section», когда используется OpenMP, однако, если #pragmas для OpenMP закомментированы,код хорошо выполняется до конца, поэтому кажется, что, когда память распределяется в параллельных потоках, она не освобождается правильно, и поэтому у нас заканчивается память.

Вопрос в том, что с памятью что-то не так?Выделение и удаление кода ниже или это ошибка в gcc v4.2.2 или OpenMP?Я также попробовал gcc v4.3 и получил тот же сбой.

int main(int argc, char** argv)
{
    std::cout << "start " << std::endl;

    {
            std::vector<std::vector<int*> > nts(100);
            #pragma omp parallel
            {
                    #pragma omp for
                    for(int begin = 0; begin < int(nts.size()); ++begin) {
                            for(int i = 0; i < 1000000; ++i) {
                                    nts[begin].push_back(new int(5));
                            }
                    }
            }

    std::cout << "  pre delete " << std::endl;
            for(int begin = 0; begin < int(nts.size()); ++begin) {
                    for(int j = 0; j < nts[begin].size(); ++j) {
                            delete nts[begin][j];
                    }
            }
    }
    std::cout << "post MT section" << std::endl;
    {
            std::vector<std::vector<int*> > nts(100);
            int begin, i;
            try {
              for(begin = 0; begin < int(nts.size()); ++begin) {
                    for(i = 0; i < 2000000; ++i) {
                            nts[begin].push_back(new int(5));
                    }
              }
            } catch (std::bad_alloc &e) {
                    std::cout << e.what() << std::endl;
                    std::cout << "begin: " << begin << " i: " << i << std::endl;
                    throw;
            }
            std::cout << "pre delete 1" << std::endl;

            for(int begin = 0; begin < int(nts.size()); ++begin) {
                    for(int j = 0; j < nts[begin].size(); ++j) {
                            delete nts[begin][j];
                    }
            }
    }

    std::cout << "end of prog" << std::endl;

    char c;
    std::cin >> c;

    return 0;
}

Ответы [ 3 ]

3 голосов
/ 02 декабря 2010

Изменение первого цикла OpenMP с 1000000 на 2000000 вызовет ту же ошибку.Это указывает на то, что проблема нехватки памяти связана с ограничением стека OpenMP.

Попробуйте установить ограничение предела стека OpenMP как неограниченное в bash с помощью

ulimit -s unlimited

Вы также можете изменить переменную среды OpenMP OMP_STACKSIZE иустановка 100 МБ или более.

ОБНОВЛЕНИЕ 1: я изменяю первый цикл на

{
    std::vector<std::vector<int*> > nts(100);
    #pragma omp for schedule(static) ordered
    for(int begin = 0; begin < int(nts.size()); ++begin) {
        for(int i = 0; i < 2000000; ++i) {
            nts[begin].push_back(new int(5));
        }
    }

    std::cout << "  pre delete " << std::endl;
    for(int begin = 0; begin < int(nts.size()); ++begin) {
        for(int j = 0; j < nts[begin].size(); ++j) {
            delete nts[begin][j]
        }
    }
}

Затем я получаю ошибку памяти при i = 1574803 в главном потоке.

ОБНОВЛЕНИЕ 2: Если вы используете компилятор Intel, вы можете добавить следующее в начало своего кода, и это решит проблему (при условии, что у вас достаточно памяти для дополнительных издержек).

std::cout << "Previous stack size " << kmp_get_stacksize_s() << std::endl;
kmp_set_stacksize_s(1000000000);
std::cout << "Now stack size " << kmp_get_stacksize_s() << std::endl;

ОБНОВЛЕНИЕ 3: Для полноты, как упомянуто другим участником, если вы выполняете какое-то числовое вычисление, лучше всего предварительно распределить все в одном новом плавающем [1000000] вместо использования OpenMP для выполнения 1000000 распределений,Это относится и к распределению объектов.

3 голосов
/ 03 декабря 2010

Я нашел эту проблему в другом месте, где не было OpenMP, а использовались только pthreads. Дополнительное потребление памяти при многопоточности представляется типичным поведением для стандартного распределителя памяти. При переключении на распределитель Hoard дополнительное потребление памяти исчезает.

0 голосов
/ 02 декабря 2010

Почему вы используете int* в качестве внутреннего члена вектора? Это очень расточительно - у вас есть 4 байта (строго sizeof(int)) данных и еще в 2-3 раза больше структуры управления кучей для каждой записи vector. Попробуйте просто, используя vector<int> и посмотрите, работает ли он лучше.

Я не эксперт по OpenMP, но это использование кажется странным в его асимметрии - вы заполняете векторы в параллельном разделе и очищаете их в непараллельном коде. Не могу сказать вам, что это не так, но это «неправильно».

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...