首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为什么在openmp并行块中使用的东西没有被Boehm收集?

为什么在openmp并行块中使用的东西没有被Boehm收集?
EN

Stack Overflow用户
提问于 2019-05-11 04:25:19
回答 1查看 152关注 0票数 0

我在我的C程序中使用Boehm-GC进行垃圾收集。我正在尝试并行化一个在数组上工作的for循环。该阵列是通过GC_malloc分配的。当循环执行完毕后,该数组在程序中不再使用。我调用GC_gcollect_and_unmap来释放数组。然而,当我使用openmp并行化for循环时,在执行完循环之后,数组永远不会被释放。这是完全相同的程序,我只是在循环周围添加了#杂注来并行化它。我试过在使用和不使用openmp并行化的情况下并排查看汇编代码,我发现数组指针正在以类似的方式进行处理,并且没有看到额外的指针被保存在任何地方。惟一的区别是,for循环是作为main函数中的一个简单循环实现的,但当我将其并行化时,openmp会创建一个新函数##name##._omp_fn并调用它。无论如何,我需要做些什么才能让Boehm GC收集数组呢?我很难发布一个MWE,因为如果程序足够小,Boehm GC根本不起作用。

这是一个没有并行化的代码摘录。

代码语言:javascript
复制
  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;                          
  }                                 

上面的代码垃圾收集函数产生的对象。以下是并行化的代码。

代码语言:javascript
复制
  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本身很难重现问题,因为垃圾收集器不会在小程序中发挥作用,但我在运行完整程序时观察到了这种行为。

EN

回答 1

Stack Overflow用户

发布于 2019-05-17 22:08:27

通过MWE本身很难重现问题,因为垃圾收集器不会在小程序中发挥作用,但当我运行完整的程序时,我正在观察这种行为。

您可以通过调用GC_gcollect()来强制垃圾回收。

此外,Boehm-GC确实释放了在并行区中分配的内存/对象。但至少有一点需要注意: OpenMP在内部使用线程池。这意味着在并行部分结束后,线程不一定会终止。那些池化的和空闲的线程可能仍然具有对堆上的对象的引用。

考虑下面的程序,它并行运行四个线程,并为每个线程分配一千个“对象”:

代码语言:javascript
复制
#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;
}

输出示例:

代码语言:javascript
复制
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不能完成被引用的对象/内存。但是很难对这个IMHO进行推理。您需要很好地理解您的编译器对openmp编译指示做了什么,以及Boehm-GC如何准确地分析程序堆栈。

关键是:一旦您重用线程(通过使用openmp运行其他程序),池化线程的堆栈将被覆盖,Boehm-GC将能够从上一次并行迭代中回收内存。从长远来看,您不会泄漏内存。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/56084397

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档