有没有办法设计一个可以在O(1)中分配和释放内存的C ++内存池(仅针对特定类)?
假设我有T级,我想在需要时只分配100 * sizeof(T)的块。但是,我如何处理在块中删除特定对象时发生的碎片?我可以为每个插槽设置一个布尔值来判断插槽是否被占用,但是我需要一个算法来为我提供下一个空闲插槽。
在O(1)中有没有任何标准的方法来实现它?我想这是一件相当普遍的事情
编辑: 图像,看看我的意思
答案 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)
中,只需交换相邻节点即可。