使用内存池第一点削除了内存泄漏的问题,第二点减低在分配内存时带来的损耗
从某种意义上讲,内存池强制你遵循一种面相会话(session-oriented)的方式进行编程,一个内存池是一个种会话上下文环境(session context),这样它使得一组对象拥有同一种生存周期。你可以控制在同意会话的一组对象。你可以在一个会话开始的时候创建一个内存池,然后使用这个内存创建你的对象。你不必关心他们的生存周期,在这个会话结束的时候,你通过销毁这个内存池销毁全部对象。
这里有3个基本的API:
APR_DECLARE(apr_status_t) apr_pool_create(apr_pool_t **newpool, apr_pool_t *parent); APR_DECLARE(void *) apr_palloc(apr_pool_t *p, apr_size_t size); APR_DECLARE(void) apr_pool_destroy(apr_pool_t *p);
我们可以通过使用apr_pool_create()创建一个内存池。这个内存池直到我们调用apr_pool_destroy()是才被销毁。apr_pool_create()的第一个参数是结果参数(result argument)是一个新创建的内存池对象(apr_pool_t)。我们通过调用apr_palloc(),可以获得一个指定内存大小的内存块
apr_pool_t *mp;
apr_pool_create(&mp, NULL);
char *buf1; buf1 = apr_palloc(mp, MEM_ALLOC_SIZE);//apr_pcalloc()返回一个已被清零的内存块
你可以使用apr_palloc()获得一个无限制的内存块,不过这并不是一个获得一个大容量内存池的好方法。内存池原本为小内存快而设计的,事实上一个内存池的初始化大小只有8k,如果你需要一个很大的内存块,比如需要一个几M字节的内存,你就不应该考虑使用内存池了
备注:在默认的情况下,通过内存池分配的内存是不会自动的返还给操作系统的。如果一个程序运行了很长时间,这他会出现一些问题,我推荐你在使用内存池的时候指定他的上限,代码如下:
#define YOUR_POOL_MAX_FREE_SIZE 32 /* apr_pool max free list size */ apr_pool_t *mp; apr_pool_create(&mp, NULL); apr_allocator_t* pa = apr_pool_allocator_get(mp); if (pa) { apr_allocator_max_free_set(pa, YOUR_POOL_MAX_FREE_SIZE); }
一个是apr_pool_clear(),另一个是apr_pool_cleanup_register()。apr_pool_clear()和apr_pool_destroy()类似,但是使用它后这个内存是可以复用的
apr_pool_t *mp; apr_pool_create(&mp, NULL); for (i = 0; i < n; i) { do_operation(..., mp); apr_pool_clear(mp); }
apr_pool_destroy(mp);
这个内存池在do_operation()中被使用,在这里一些内存块被分配出来,如果在do_operation()之外你不需要这些内存,你可以调用apr_pool_clear(),这样你就可以减少内存使用数量
最后一个议题是关于内存池子池的问题(sub pool),每一个内存池可以有一个父内存池。因此内存池可以构建成一个树形结构(tree),apr_pool_create()的第二个参数就是父内存池,当你使用NULL作为父内存池的时候,新创建的内存池将被编程根内存池,你可以在这个内存池下创建字内存池。当你在一个树形内存池中使用apr_pool_destroy()的时候,这个内存池的子内存池也会被销毁。当你调用apr_pool_clear()的时候,当前的内存池仍然可用,但是他的子内存池被销毁。只要子内存池被销毁上一级的清理函数将会被调用。
当你相传递一个NULL作为清理的回调函数时,你必须使用apr_pool_cleanup_null代替NULL,不然会引起bug
/* apr_pool_cleanup_register(mp, ANY_CONTEXT_OF_YOUR_CODE, ANY_CALLBACK_OF_YOUR_CODE, NULL); THIS IS A BUG */ apr_pool_cleanup_register(mp, ANY_CONTEXT_OF_YOUR_CODE, ANY_CALLBACK_OF_YOUR_CODE, apr_pool_cleanup_null);