Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/57.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C中的内存池-内存管理_C_Memory Management_Shared Libraries_Pool - Fatal编程技术网

C中的内存池-内存管理

C中的内存池-内存管理,c,memory-management,shared-libraries,pool,C,Memory Management,Shared Libraries,Pool,我正在用C编写一个跨平台共享库。该库的工作流程如下: lib *handle = lib_init(); result = lib_do_work(handle); lib_destroy(handle); 通常,用户会在应用程序启动时初始化它,并在应用程序结束时关闭它lib\u do\u work()通常在一秒钟内被调用多次。因此,为了避免每次调用的内存分配和释放,我使用了一种池机制。这样,我要求池返回我需要的结构实例。池将返回一个未使用的实例,如果没有可用的实例,则创建一个新实例。这个新实

我正在用C编写一个跨平台共享库。该库的工作流程如下:

lib *handle = lib_init();
result = lib_do_work(handle);
lib_destroy(handle);
通常,用户会在应用程序启动时初始化它,并在应用程序结束时关闭它
lib\u do\u work()
通常在一秒钟内被调用多次。因此,为了避免每次调用的内存分配和释放,我使用了一种池机制。这样,我要求池返回我需要的结构实例。池将返回一个未使用的实例,如果没有可用的实例,则创建一个新实例。这个新实例也将添加到池中,以便下次可以使用它

对我的库的任何API调用都以函数调用
reset\u pool()
开始,该函数使池中的所有元素再次可用。此池作为
lib\u destroy()
调用的一部分被销毁。在我的测试中,我观察到有时我的池会得到100000多个结构实例实例


我想知道这是处理记忆的好方法吗?任何帮助都会很好。

正如评论中已经指出的那样,只有分析才能告诉您分配和解除分配是否是应用程序中的瓶颈。此外,如果您的系统始终只分配和释放相同大小的对象,那么默认实现可能会执行得相当好

通常,池通过预分配块或元素来提供分配优化。块被分割成单独的元素以满足单独的分配请求。当池耗尽时,将分配一个新块。这是一种分配优化,因为更少地调用库分配器更便宜

池分配器还可以帮助减少碎片。如果应用程序分配和解除分配不同大小的对象,并具有不同的生命周期,那么碎片化的可能性就会增加(默认分配器中的合并代码必须做更多的工作)。如果为每个不同大小的对象创建了池分配器,并且每个池块的大小相同,那么这将有效地消除碎片

(正如Felice指出的,还有另一种池,它预先为应用程序分配固定数量的内存,以确保应用程序使用的内存不会超过配置的内存。)

释放时,可以将单个元素放置到自由列表中。但是您的
reset_pool
实现只需遍历块,释放每个块,然后分配一个新块

下面的内容有点过于简单。它只涉及一种元素。池大小需要调整为适合您的应用程序的合理大小。假设数据结构如下:

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);
}
void pool_init(元素_pool*p){/*…*/}
元素*pool\u alloc(元素*pool*p){
元素*e=p->自由列表;
如果(e)p->freelist=e->next;
否则会{
如果(p->i<池大小){
e=&p->pools->block[p->i];
p->i+=1;
}否则{
pool_block*b=pool_block_create();
b->next=p->pool;
p->pools=b;
p->i=0;
}
}而(e==0);
返回e;
}
元素*pool\u dealloc(元素*pool*p,元素*e){
e->next=p->自由列表;
p->freelist=e;
}
无效池重置(元素池*p){
*b座泳池;
而((b=p->pool)){
p->pools=b->next;
池、块、破坏(b);
}
池_init(p);
}

我不知道您当前的体系结构是否过于复杂,但通常情况下,当所有池实例都很忙时,池会限制池实例和队列请求的数量。

过早优化是万恶之源。您是否测量到每次调用的分配/解除分配都会降低应用程序的速度?我不确定这是否是过早的优化。我这样做的唯一原因是,1-我不需要每次都做分配。2-我不必到处管理内存。我所要做的就是在每个API方法的开头重置_池。谢谢。我有一个类似的实现,但没有多个池。每个结构都有一个动态增长的池。也就是说,structa将有一个池,structb将有另一个池。我想知道像您这样做有什么好处吗?同样在我的池实现中,我最初只分配一个元素。然后为每个调用增加2倍。我的重置池只会将索引恢复为0。@Appu:我不完全理解你的池是如何工作的,所以我无法将你的实现与我建议的实现进行比较。如果您可以在关于分配、取消分配和重置函数的问题中添加一点代码,我可以评论一下它们在多大程度上满足了您的目标。感谢你没有说清楚。您可以在这里看到我的池实现。