在O上运行的内存池(1)

时间:2012-11-09 20:00:09

标签: c++ memory-management

有没有办法设计一个可以在O(1)中分配和释放内存的C ++内存池(仅针对特定类)?

假设我有T级,我想在需要时只分配100 * sizeof(T)的块。但是,我如何处理在块中删除特定对象时发生的碎片?我可以为每个插槽设置一个布尔值来判断插槽是否被占用,但是我需要一个算法来为我提供下一个空闲插槽。

在O(1)中有没有任何标准的方法来实现它?我想这是一件相当普遍的事情

编辑: 图像,看看我的意思 pic

3 个答案:

答案 0 :(得分:3)

此解决方案正在使用额外的内存(可能是您想要的内容,也可能不是您想要的内容),如果您尝试连续两次释放一块,也会遇到问题。

预分配足够的内存。将它分成块,每个对象一个。保留一个免费块的列表。分配新对象时,从空闲块列表的顶部选择一个块。释放对象时,将其块添加到空闲块列表中。这两个操作都是O(1)。

它看起来像这样:

初​​始化:

char* mem = new char[CHUNK_SIZE * OBJ_COUNT];
std::list<char*> free_chunks;
for (char* c = mem, int i = 0; i < OBJ_COUNT; ++i)
{
   free_chunks.push_back(c);
   c += CHUNK_SIZE;
}

获取新的分配块:

   if(free_chunks.size() > 0)
   {
    char* c = free_chunks.back();
    free_chunks.pop_back();
    return c;
   }
   else{ // Error, not enough memory... }

解除分配后返回一个块:

free_chunks.push_back(c);

答案 1 :(得分:1)

您可以使用O(1)对象重新实现简单对象池。但是你的对象需要有指向下一个对象的内部指针。 池内部构造函数有些预先计算:

pool.reserve(capacity); //std::vector<Object*>
for (int i = 0; i < capacity; ++i) {
    pool.push_back(new Object());
}
for (int i = 0; i < capacity-1; ++i) {
    pool[i]->setNext(pool[i+1].get());
}
first_available = pool[0].get(); //variable where you store first free object 
pool[capacity-1]->setNext(NULL);

然后getObject方法是:

getObject* getObject()
{
    getObject* obj = first_available;
    first_available = first_available->getNext();
    return obj;
}

void returnObject(Object* obj)
{
    obj->setNext(first_available);
    first_available = obj;
}

希望它有所帮助。

答案 2 :(得分:1)

您只有一般内存分配问题的碎片,其中请求任意长度的块。这里的问题是给定这种内存布局:

@@@@@@---@--@-@@@@

(其中@表示正在使用,-表示免费)

尽管共有6个空闲块,但您无法分配4个连续块。所以你必须增加管理空间的总量(如果可能的话)。 同样在这个一般情况下,决定选择哪个地址并不简单,并且有几种策略(首先适合,最差等等)会影响碎片程度。

在您的情况下,问题变得非常容易,因为您知道要分配的区域将始终与某个整数k的大小完全相同(比如k = sizeof(T))。 这意味着您将始终拥有完美贴合的块,您可以根据自己的喜好进行组织。只需处理可用空间就好像它是一个链表,并始终使用列表中的第一项来回答内存分配请求。

@@@---@@@------@@@@@@@@@---@@@ (k=3)

现在,如果你想分配大块来分摊分配,你可以保留一个特定块中使用了多少个槽的额外计数器,以便在它被清空时释放该块(如果你想缩小你的水槽!)。

如果您坚持始终从最常用的块中分发新的内存块,则可以使用另一个列表来指示哪个块最充分。由于您始终只能将已用插槽的数量更改为1,因此您可以将该列表保存在O(1)中,只需交换相邻节点即可。