Почему мои выделенные блоки памяти не согласованы? - PullRequest
1 голос
/ 07 февраля 2020

Я пытаюсь написать распределитель памяти в c ++ для класса, и по какой-то причине мои выделенные блоки неправильно хранят свои данные, когда программа пытается их освободить.

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

Программа может также освободить блоки памяти, вставив их обратно в список и отыскивая его «собеседника» (блок, который был создан, когда его родительский элемент был разделен), чтобы попытаться объединить их, что он делает рекурсивно так долго, как может. Это делается путем проверки адреса памяти блока.

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

allo c ():

`void *BuddyAllocator::alloc(int length)
{
  cout << "Block size " << length << " requested" << endl;
  int rounded_length = round_up(length);
  if (rounded_length <= available_mem)
  {
    cout << "Searching for block size " << rounded_length << endl;
    bool loop = true;
    while (loop)
    {
      for (int i = 0; i <= FreeList.size(); i++)
      {
        if (FreeList[i].head != nullptr)
        {
          BlockHeader *iter = FreeList[i].head;
          if (iter->block_size == rounded_length && iter->free)
          {
            cout << "Suitable block found, returning block "<<iter<<" size: " << iter->block_size << endl;
            loop = false;
            FreeList[i].remove(iter);
            available_mem -= iter->block_size;
            return (void *)iter;
          }
          else if (iter->block_size > rounded_length && iter->free)
          {
            cout << "Large block found, splitting block size: " << iter->block_size << endl;
            split(iter);
            break;
          }
        }
      }
    }
  }
  else
  {
    cout << "Not enough memory available" << endl;
  }
  return nullptr;
}`
split: `void *BuddyAllocator::split(BlockHeader *block)
{
  int level = log2((double)block->block_size / basic_block_size);
  BlockHeader *left = block;
  int child_size = block->block_size / 2;
  left->block_size = child_size;
  BlockHeader *right = new ((char *)block + left->block_size) BlockHeader(child_size, true);
  FreeList[level].remove(block);
  FreeList[level - 1].insert(right);
  cout << "inserting right block into level: " << level - 1 << " size: " << child_size << endl;
  FreeList[level - 1].insert(left);
  cout << "inserting left block into level: " << level - 1 << " size: " << child_size << endl;
}`

free ():

`void BuddyAllocator::free(void *a)
{
  BlockHeader *to_free = (BlockHeader *)a;
  int level = log2((double)to_free->block_size / basic_block_size); //find level to insert block into
  FreeList[level].insert(to_free);
  BlockHeader *iter = to_free->next;
  cout << "Freeing memory: " << to_free << endl
       << "Block size: " << to_free->block_size << endl;

  while (1 == 1)
  {
    if (((char *)iter == ((char *)to_free + to_free->block_size))) //check addresses to check for match
    {
      cout << "Joining segments" << endl;
      BlockHeader *joined_block = new ((char *)to_free) BlockHeader(to_free->block_size * 2, true);
      joined_block->next = nullptr;
      FreeList[level].remove(iter);
      FreeList[level].remove(to_free);
      free(joined_block);
      break;
    }
    else if ((char *)iter == ((char *)to_free - to_free->block_size)) //check addresses to check for match
    {
      cout << "Joining segments" << endl;
      BlockHeader *joined_block = new ((char *)iter) BlockHeader(to_free->block_size * 2, true);
      joined_block->next = nullptr;
      FreeList[level].remove(iter);
      FreeList[level].remove(to_free);
      free(joined_block);
      break;
    }
    else if (iter != nullptr)
    {
      iter = iter->next;
    }
    else
    {
      cout << "Buddy not found :(" << endl;
      break;
    }
  }
}`

Это ошибка, которую я имею: enter image description here

Вы можете видеть это, когда блок 0x7 .. .410 выделен, он правильно показывает, что блок имеет размер 1024, но когда я пытаюсь освободить тот же адрес, он показывает размер 111138594 (действительно неправильно). Это не всегда происходит, как вы можете видеть, когда блок 0x7 ... a210 показывает размер 128 как при выделении, так и при освобождении.

Мой код выглядит правильно и с помощью простых тестов (выделите один, освободите то же самое и вот оно) это работает, но я не могу понять, почему это не работает, когда я пытаюсь автоматически распределить / освободить блоки. Кто-нибудь может помочь?

1 Ответ

3 голосов
/ 07 февраля 2020

Распределители обычно не возвращают узел структуры данных (BlockHeader в вашем случае). Они возвращают пустую область в нем как void *. Если ваши абоненты хранят данные в возвращаемом значении распределителя, они будут перезаписывать его поля.

Простой «выделите, затем освободите» будет работать. Проблема в том, что если вы используете возврат распределителя.

Точно так же, бесплатно, вам нужно найти BlockHeader из void * внутри него. Обычно вы делаете это, вычитая смещение поля или sizeof(BlockHeader)

...