正如评论中已经指出的那样,只有分析才能告诉您分配和释放是否是您的应用程序的瓶颈。此外,如果您的系统始终只分配和释放相同大小的对象,那么默认实现可能会执行得相当好。
通常,池通过预先分配块或元素来提供分配优化。该块被分割成单独的元素以满足单独的分配请求。当池耗尽时,分配一个新块。这是一种分配优化,因为减少对库分配器的调用会更便宜。
池分配器还可以帮助减少碎片。如果应用程序分配和释放具有不同生命周期的不同大小的对象,那么碎片的机会就会增加(并且默认分配器中的合并代码必须做更多的工作)。如果为每个不同大小的对象创建一个池分配器,并且每个池块的大小相同,这将有效地消除碎片。
(正如 Felice 指出的那样,还有另一种类型的池,它预先分配了固定数量的内存供应用程序使用,以确保应用程序使用的内存不会超过预配的内存。)
在解除分配时,可以将单个元素放置到空闲列表中。但。您的reset_pool
实现可以只遍历块,释放每个块,然后分配一个新块。
以下内容比较简单。它只处理一种元素。POOL_SIZE 需要调整为适合您的应用程序的合理值。假设数据结构如下:
typedef struct element {
struct element *next;
/* ... */
} element;
typedef struct pool_block {
struct pool_block *next;
struct element block[POOL_SIZE];
} pool_block;
typedef struct element_pool {
struct pool_block *pools;
struct element *freelist;
int i;
} element_pool;
然后,API 看起来像:
void pool_init (element_pool *p) { /* ... */ }
element * pool_alloc (element_pool *p) {
element *e = p->freelist;
if (e) p->freelist = e->next;
else do {
if (p->i < POOL_SIZE) {
e = &p->pools->block[p->i];
p->i += 1;
} else {
pool_block *b = pool_block_create();
b->next = p->pools;
p->pools = b;
p->i = 0;
}
} while (e == 0);
return e;
}
element * pool_dealloc (element_pool *p, element *e) {
e->next = p->freelist;
p->freelist = e;
}
void pool_reset (element_pool *p) {
pool_block *b;
while ((b = p->pools)) {
p->pools = b->next;
pool_block_destroy(b);
}
pool_init(p);
}