我在我的 C 程序中使用 Boehm-GC 进行垃圾收集。我正在尝试并行化一个适用于数组的 for 循环。数组是通过 GC_malloc 分配的。循环执行完毕后,程序中不再使用数组。我调用 GC_gcollect_and_unmap 来释放数组。但是,当我使用 openmp 并行化 for 循环时,循环执行完成后数组永远不会被释放。这是完全相同的程序,我只在循环周围添加#pragmas 以使其并行化。我尝试在有和没有 openmp 并行化的情况下并排查看汇编代码,我看到数组指针正在以类似的方式处理,并且没有看到额外的指针被保留在任何地方。唯一的区别是 for 循环是作为主函数中的一个简单循环实现的,但是当我并行化它时,openmp 创建一个新函数##name##._omp_fn 并调用它。无论如何,我需要做些什么来让 Boehm-GC 收集阵列吗?我很难发布 MWE,因为如果程序足够小,Boehm-GC 根本不会启动。
这是没有并行化的代码摘录。
struct thing {
float* arr;
int size;
}
int l=10;
static thing* get_randn(void) {
thing* object = (thing*)GC_malloc(sizeof(struct {float* arr, int size}));
object->arr=malloc(sizeof(float)*l);
void finalizer(void *obj, void* client_data)
{
printf("freeing %p\n", obj);
thing* object = (thing*)obj;
free(object->arr);
}
GC_register_finalizer(object, &finalizer, NULL, NULL, NULL);
float *arr = object->arr;
int t_id;
for (t_id = 0; t_id<l; t_id++) {
torch_randn(arr+t_id);
}
return object;
}
上面的代码垃圾收集了函数产生的对象。以下是并行化的代码。
struct thing {
float* arr;
int size;
}
int l=10;
static thing* get_randn(void) {
thing* object = (thing*)GC_malloc(sizeof(struct {float* arr, int size}));
object->arr=malloc(sizeof(float)*l);
void finalizer(void *obj, void* client_data)
{
printf("freeing %p\n", obj);
thing* object = (thing*)obj;
free(object->arr);
}
GC_register_finalizer(object, &finalizer, NULL, NULL, NULL);
float *arr = object->arr;
int t_id;
#pragma omp parallel num_threads(10)
{
#pragma omp for
for (t_id = 0; t_id<l; t_id++) {
torch_randn(arr+t_id);
}
}
return object;
}
对于此代码,对象不会被垃圾收集。仅通过 MWE 本身很难重现该问题,因为垃圾收集器不会启动小程序,但是当我使用完整的程序运行时,我正在观察这种行为。