Последовательные распределители - PullRequest
3 голосов
/ 28 февраля 2012

У меня есть код с большим количеством malloc s и mallocs API для конкретного устройства (я программирую на GPU, поэтому cudaMalloc).

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

Поскольку я инкапсулировал свои глобальные данные в структурах, освобождение довольно длинное, но, по крайней мере, я могу разбить их на отдельные функции. С другой стороны, я хотел бы более короткое решение. Кроме того, автоматический освобождение памяти уменьшит риск утечек памяти, если я забуду явно записать освобождение в функции глобального распределителя.

Мне было интересно, можно ли написать некую шаблонную оболочку класса, которая позволит мне «регистрировать» переменные во время процесса malloc / cudaMalloc, а затем в конце симуляции выполнить массу освобождение от петель (отмена регистрации). Чтобы быть ясным, я не хочу печатать отдельные освобождения (free / cudaFree s), потому что опять-таки это долго и нежелательно, и предполагается, что все, что я зарегистрирую, не будет освобождено, пока симуляция устройства завершен, и основной завершается.

Преимущество здесь состоит в том, что если я зарегистрирую новую переменную продолжительности симуляции, она автоматически освободится, поэтому я не рискую забыть ее освободить и создать утечку памяти.

Возможна ли такая обертка?

Вы бы предложили это сделать?

Если да, то как?

Заранее спасибо!

Ответы [ 3 ]

3 голосов
/ 28 февраля 2012

Идея:

Создайте обе функции, одну, которая выделяет память и предоставляет действительные указатели после регистрации их в «списке» выделенных указателей.Во втором методе зациклите этот список и освободите все указатели:

// ask for new allocated pointer that will be registered automatically in list of pointers.
pointer1 = allocatePointer(size, listOfPointers);
pointer2 = allocatePointer(size, listOfPointers);

...
// deallocate all pointers
deallocatePointers(listOfPointers);

Четно, вы можете использовать разные listOfPointers в зависимости от объема вашей симуляции:

listOfPointer1 = getNewListOfPointers();
listOfPointer2 = getNewListOfPointers();
....
p1 = allocatePointer(size, listOfPointer1);
p2 = allocatePointer(size, listOfPointer2);
...
deallocatePointers(listOfPointers1);
...
deallocatePointers(listOfPointers2);
1 голос
/ 28 февраля 2012

Есть много способов снять кожу с кошки, как они говорят.

Я бы порекомендовал Thrust's device_vector в качестве инструмента управления памятью.Он абстрагирует распределение, освобождение и memcpy в CUDA.Это также дает вам доступ ко всем алгоритмам, которые предоставляет Thrust.

Я бы не рекомендовал хранить случайные списки несвязанных указателей, как рекомендует Тио Пепе.Вместо этого вы должны инкапсулировать связанные данные в класс.Даже если вы используете thrust::device_vector, вы можете инкапсулировать несколько связанных векторов и операций над ними в класс.

0 голосов
/ 28 февраля 2012

Наилучшим выбором, вероятно, является использование интеллектуальных указателей из библиотеки повышения C ++, если это возможно.

Если нет, то лучшее, на что вы можете надеяться в C, - это дизайн программы, который позволяет вам записывать распределение и освобождение в одном месте.Возможно, что-то вроде следующего псевдокода:

while(!terminate_program)
{
  switch(state_machine)
  {
    case STATE_PREOPERATIONAL:
      myclass_init(); // only necessary for non-global/static objects
      myclass_mem_manager();
      state_machine = STATE_RUNNING;
    break;

    case STATE_RUNNING:
      myclass_do_stuff();
      ...
    break;

    ...

    case STATE_EXIT:
      myclass_mem_manager();
      terminate_program = true;
    break;
  }


void myclass_init()
{
  ptr_x = NULL; 
  ptr_y = NULL;

  /* Where ptr_x, ptr_y are some of the many objects to allocate/deallocate.
     If ptr is a global/static, (static storage duration) it is 
     already set to NULL automatically and this function isn't 
     necessary */
}

void myclass_mem_manager()
{
  ptr_x = mem_manage (ptr_x, items_x*sizeof(Type_x));
  ptr_y = mem_manage (ptr_y, items_y*sizeof(Type_y));
}


static void* mem_manage (const void* ptr, size_t bytes_n)
{
  if(ptr == NULL)
  {
    ptr = malloc(bytes_n);

    if (ptr == NULL)
    {} // error handling
  }
  else
  {
    free(ptr);
    ptr = NULL;
  }

  return ptr;
}
...