2010-12-02 2 views
5

В нижеприведенном тестовом случае на 32-разрядных машинах (бросание std :: bad_alloc) в цикле после сообщения «пост MT-раздела» при использовании OpenMP используется ниже, если #pragmas for OpenMP закомментирован, код заканчивается до завершения, поэтому появляется, что, когда память распределяется в параллельных потоках, она не освобождается правильно и, следовательно, у нас заканчивается память.Утечка памяти при использовании 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; 
} 
+0

Когда я запускаю это под Windows, построенным с помощью компилятора Intel, мои распределения начинают сбой в первом цикле из-за попадания предела 2gb для 32-битного процесса. Возможно ли, что накладные расходы OpenMP просто подталкивают ваш процесс к любому пределу на вашей платформе? – Scott 2010-12-02 16:00:59

+0

@Scott Danahy Попробуйте изменить тестовый кейс, чтобы сократить все распределения пополам, этот тест работал с пределом 4 ГБ. – WilliamKF 2010-12-02 19:28:09

ответ

3

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

0

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

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

+0

@Steve Townsend Этот тестовый пример предназначен для отображения проблемы, а не для фактического использования кода. Массив из пяти ints в каждой записи помогает использовать память для демонстрации утечки. Если сделать код более эффективным с точки зрения памяти, это приведет к тому, что отказ будет задерживаться до тех пор, пока не будет потреблено еще больше памяти. – WilliamKF 2010-12-02 15:24:07

3

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

Попробуйте установить предел стека OpenMP для снятия ограничения в Баш с

ulimit -s unlimited 

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

UPDATE 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] 
     } 
    } 
} 

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

UPDATE 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; 

UPDATE 3: Для полноты, как упомянуто другим членом, если вы выполняете некоторые численные расчеты, то лучше заранее выделить все в одном нового поплавка [1000000] вместо того, чтобы использовать OpenMP сделать 1000000. распределение. Это также относится к распределению объектов.

 Смежные вопросы

  • Нет связанных вопросов^_^