Я написал код openmp на C ++, в котором есть динамическая выделенная память в параллельной области, область находится в цикле while. Динамически выделяемая память освобождается в конце параллельной области в каждом цикле. Я слежу за памятью через / proc / self / stat на машине linux после каждого выделения и освобождения. Я нахожу немного меньше памяти в размере резидентного набора. Почему это так ? Код что-то вроде —
float *dynm;
while(condition)
{
pragma omp parallel shared(list of variables) private(dynm)
{
read_values_from_/proc/self/stat_print_rss;
dynm = new float[size];
read_values_from_/proc/self/stat_print_rss;
pragma omp for schedule(static, chunk) nowait
for(counter)
{
do_operation;
}
delete []dynm;
read_values_from_/proc/self/stat_print_rss;
}
}
Измерение RSS не очень точный способ поиска утечек памяти из-за очень сложного способа его вычисления. Существуют специальные отладчики памяти, такие как valgrind
или тот, который встроен в glibc
это может сказать вам, если память протекает. Вы также должны понимать, что glibc
использует два совершенно разных механизма для динамического выделения памяти.
Для больших распределений он выполняет частные анонимные карты памяти, используя mmap(2)
системный вызов. Этот метод может выделять только блоки с размерами, кратными размеру системной страницы (4 КиБ в большинстве современных архитектур), поэтому он не подходит для небольших распределений. Это даже не подходит для больших выделений, когда слишком много памяти будет потрачено впустую, например если вы хотите выделить блок из 17 КиБ, то нужно выделить 20 КиБ (5 раз по 4 КиБ) и 15% памяти будет потрачено впустую.
Для меньших распределений используется предоставляемая системой куча. Есть что-то под названием разрыв системы, где заканчивается сегмент данных процесса. Это может быть перемещено с brk(2)
Системный вызов, чтобы выделить больше памяти и вниз, чтобы освободить ее. Поскольку для каждого процесса существует только одна область кучи, а ОС рассматривает ее как один блок, в нее встроен специальный менеджер кучи. glibc
это может далее подразделить этот блок на меньшие распределения.
C ++ new
звонки оператора malloc(3)
от glibc
выполнить выделение памяти. malloc(3)
вызовы одного из двух механизмов выделения памяти, описанных выше, в зависимости от размера выделяемого блока памяти. C ++ delete
звонки оператора free(3)
от glibc
который является аналогом освобождения malloc(3)
, То, что происходит после освобождения блока памяти, во многом зависит от того, как он был выделен в первую очередь.
Память, которая была выделена с помощью mmap(2)
механизм освобождается путем его отображения munmap(2)
, Это удаляет отображение памяти из виртуального адресного пространства процесса и освобождает страницы физической памяти, которые использовались для выделения ресурсов.
Все гораздо сложнее для памяти, которая была выделена в куче, и в большей степени зависит от алгоритма, который используется для ее управления. Если освобождаемый блок находится не в конце кучи, а скорее где-то еще, размер кучи не может быть уменьшен, так как существуют другие выделения в верхних адресах памяти. Это только одна из многих форм, в которых так называемые фрагментация кучи проявляет себя. Другая возможная причина, по которой не наблюдается уменьшение используемой памяти, заключается в том, что менеджер кучи может принять решение не возвращаться назад к позиции разрыва в ожидании возможных будущих распределений и вызова brk(2)
это дорогая операция.
Других решений пока нет …