c++ O(1)上运行的内存池

s4chpxco  于 2023-02-01  发布在  其他
关注(0)|答案(3)|浏览(144)

有没有一种方法可以设计一个C++内存池(只针对一个特定的类),它可以在O(1)中分配和释放内存?
假设我有一个类T,我想在需要的时候只分配100*sizeof(T)的块,但是当一个特定的对象在块中被删除时,我该如何处理碎片呢?我可以为每个槽指定一个布尔值来判断这个槽是否被占用,但是我需要一个算法来给予我下一个空闲的槽。
在O(1)中有什么标准的方法来实现这个吗?我想这是一个相当普遍的事情
edit:image以了解我的意思

ktecyv1j

ktecyv1j1#

这个解决方案使用额外的内存(这可能是你想要的,也可能不是你想要的),如果你试图连续两次释放一个块,你也会遇到问题。
预先分配足够的内存。将内存分成块,每个对象一个。保留一个空闲块列表。当你分配一个新对象时,从空闲块列表的顶部选择一个块。当你释放一个对象时,将它的块追加到空闲块列表中。这两个操作都是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);
pnwntuvh

pnwntuvh2#

你可以用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;
}

希望有帮助。

kqlmhetl

kqlmhetl3#

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

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

(其中@表示正在使用,-表示空闲)
虽然总共有6个空闲块,但您不能分配4个连续的块。因此,您必须增加受管理空间的总量(如果可能)。此外,在此一般情况下,决定选择哪个地址并非微不足道,并且有几个策略(最先匹配、最差匹配等)会影响碎片的程度。
在您的示例中,问题要简单得多,因为您知道要分配的区域大小始终为某个整数k(比如k = sizeof(T))。这意味着你总是会有完美的拟合块,你组织就像你喜欢的。简单地处理空闲空间,就好像它是一个链表一样,并且总是使用链表中的第一项来响应内存分配请求。

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

现在,如果你想在大块中分配以摊销分配,你可以保持一个额外的计数器,计数在一个特定的块中使用了多少个插槽,以便在它为空时释放该块(如果你想缩小插槽库的话!)
如果你坚持总是从最常用的块中分配新的内存块,你可以使用一个额外的列表来指示哪个块是最满的。因为你总是只能将已用插槽的数量改变一个,你可以保持该列表以O(1)排序,只需交换相邻的节点。

相关问题