Трудно воспроизвести проблему самостоятельно с помощью MWE, потому что сборщик мусора не запускается для небольших программ, но я наблюдаю такое поведение при запуске с полной программой.
Вы можете форсировать сборку мусора, вызывая GC_gcollect()
.
Также Boehm-GC определенно освобождает память / объекты, расположенные в параллельных секциях.Но есть по крайней мере одно предостережение: OpenMP использует внутренний пул потоков.Это означает, что потоки не обязательно заканчиваются после окончания параллельной секции.Эти объединенные в пул и свободные потоки могут все еще иметь ссылки на объекты в куче.
Рассмотрим следующую программу, которая запускает четыре потока параллельно и выделяет тысячу «объектов» на поток:
#define GC_THREADS
#include <assert.h>
#include <stdio.h>
#include <omp.h>
#include <gc.h>
#define N_THREADS 4
#define N 1000
// count of finalized objects per thread
static int counters[N_THREADS];
void finalizer(void *obj, void* client_data)
{
#pragma omp atomic
counters[*(int*)obj]++;
}
int main(void)
{
GC_INIT();
GC_allow_register_threads();
int i;
for(i = 0; i < N_THREADS; i++) {
counters[i] = 0;
}
// allocate lots integers and store the thread id in it
// execute N iterations per thread
#pragma omp parallel for num_threads(4) schedule(static, N)
for (i = 0; i < N_THREADS*N; i++)
{
struct GC_stack_base sb;
GC_get_stack_base(&sb);
GC_register_my_thread(&sb);
int *p;
p = (int*)GC_MALLOC(4);
GC_REGISTER_FINALIZER(p, &finalizer, NULL, NULL, NULL);
*p = omp_get_thread_num();
}
GC_gcollect();
for(i = 0; i < N_THREADS; i++) {
printf("finalized objects in thread %d: %d of %d\n", i, counters[i], N);
}
return 0;
}
Пример вывода:
finalized objects in thread 0: 1000 of 1000
finalized objects in thread 1: 999 of 1000
finalized objects in thread 2: 999 of 1000
finalized objects in thread 3: 999 of 1000
Числа означают, что потоки с 1 по 3 объединены и все еще содержат ссылку на объект последней итерации.Поток 0 является основным потоком, который продолжает выполнение и, таким образом, теряет ссылку на последнюю итерацию в стеке.
Редактировать: @maddy: Я не думаю, что это имеет какое-либо отношение крегистры или оптимизация компилятора.Как правило, компилятор может выполнять только те оптимизации, которые гарантированно не изменят поведение программы.По общему признанию, ваша проблема может быть угловой.
Согласно Wikipedia , Boehm-GC ищет ссылки в программном стеке.В зависимости от того, как компилятор преобразует прагмы openmp в код, вполне может оказаться, что стековый фрейм, содержащий ссылку на кучу, все еще действителен, когда поток переходит в состояние ожидания.В этом случае Boehm-GC по определению не может завершить указанный объект / память.Но об этом ИМХО сложно рассуждать.Вам нужно было бы хорошо понять, что ваш компилятор делает с прагмами openmp и как именно Boehm-GC анализирует стек программ.
Суть в том, как только вы повторно используете потоки (запуская что-то еще сopenmp) стеки объединенных потоков будут перезаписаны, и Boehm-GC сможет восстановить память из предыдущей параллельной итерации. В долгосрочной перспективе у вас нет утечки памяти.