我试图用C ++为一个类编写一个内存分配器,由于某种原因,当程序试图释放它们时,我分配的块无法正确保存其数据。
基本上有一个列表向量,其中包含不同大小的存储块。当请求存储器的一部分时,找到合适的块并将其返回给用户。如果在其中一个列表中未找到合适的块,但是有一个更大的块,则将较大的块从列表中删除,将其分成两半,并将这两个块插入下面的级别。
程序还可以通过将内存块重新插入列表并查找其“伙伴”(拆分其父对象时创建的另一个块)来尝试合并它们,以释放它们,从而释放它们。它可以。它通过检查块的内存地址来实现。
由于分配和免费通话之间的某种原因,我的内存块被更改了,我不确定为什么。
alloc():
`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;
}`
免费():
`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;
}
}
}`
您可以看到,在分配块0x7 ... a410时,它正确显示该块的大小为1024,但是当我尝试释放相同的地址时,它显示的大小为111138594(确实是错误的)。它并不总是发生,如您所见,块0x7 ... a210在分配时和释放时都显示大小为128。
我的代码看起来不错,并通过简单的测试(分配一个,释放相同的一个,就是这样),它可以工作,但是当我尝试自动分配/释放块时,我无法弄清楚为什么它不起作用。谁能帮忙?
分配器通常不返回数据结构节点(在您的情况下为BlockHeader)。他们将其中的空白区域返回为void *
。如果调用者将数据存储在分配器的返回值中,则它们将覆盖其字段。
简单的“分配,然后免费”将起作用。问题是您是否使用分配器的返回值。
类似地,免费,您需要从其中的void *
查找BlockHeader。通常,您可以通过减去字段偏移量或sizeof(BlockHeader)