apr_pool中主要有3个对象,allocator、pool、block。pool从allocator申请内存,pool销毁的时候把内存归还allocator,allocator销毁的时候把内存归还给系统,allocator有一个owner成员,是一个pool对象,allocator的owner销毁的时候,allocator被销毁。在apr_pool中并无block这个单词出现,这里大家可以把从pool从申请的内存称为block,使用apr_palloc申请block,block只能被申请,没有释放函数,只能等pool销毁的时候才能把内存归还给allocator,用于allocator以后的pool再次申请。
我给的例子中并没有出现创建allocator的函数,而是使用的默认全局allocator。apr_pool提供了一系列函数操作allocator,可以自己调用这些函数:

apr_allocator_create
apr_allocator_destroy
apr_allocator_alloc
apr_allocator_free
创建销毁allocator
apr_allocator_owner_set
apr_allocator_owner_get
设置获取owner
apr_allocator_max_free_set 设置pool销毁的时候内存是否直接归还到操作系统的阈值
apr_allocator_mutex_set
apr_allocator_mutex_get
设置获取mutex,用于多线程

另外还有设置清理函数啊等等,不说了。自己去看include里的头文件好了:apr_pool.h和apr_allocator.h两个。源码.c文件里,APR_DECLARE宏声明的函数即是暴露给外部使用的函数。大家也可以仿造Loki(后文将介绍Loki)写个顶层类重载operator new操作子,其中调用apr_palloc,使用到的数据结构继承该类,则自动从pool中申请内存,如要完善的地方很多,自行去研究吧。
可以看出来apr_pool的一个大缺点就是从池中申请的内存不能归还给内存池,只能等pool销毁的时候才能归还。为了弥补这个缺点,apr_pool的实际使用中,可以申请拥有不同生命周期的内存池(类似与上面的例子程序中不同的大括号代表不同的生命周期,实际中,尽可以把大括号中的内容想象成不同的线程中的......),以便尽可能快的回收不再使用的内存。实际中apache也是这么做的。因此apr_pool比较适合用于内存使用的生命期有明显层次的情况。
至于担心allocator中的内存一旦申请就再也不归还给操作系统(当然最后进程退出的时候你可以调用销毁allocator归还,实际中网络服务程序都是一直运行的,找不到销毁的时机)的问题,就是杞人忧天了,如果在某一时刻,系统占用的内存达到顶峰,意味着以后还会有这种情况。是否能接受这个解释,就看个人的看法和系统的业务需求了,不能接受,就使用其它的内存池。个人觉得apr_pool还是很不错的,很多服务系统的应用场景都适用。
(2)obstack。glibc自带的内存池。原理与apr_pool相同。详细使用文档可以参阅
http://www.gnu.org/software/libc/manual/html_node/Obstacks.html。推荐apr_pool,这个就不再多说了。
(3)AutoFreeAlloc。许式伟的专栏http://blog.csdn.net/xushiweizh/category/265099.aspx
这个内存池我不看好。这个也属于一个变长的内存池,内存申请类似与apr_pool的pool/block层面,一次申请大内存作为pool,用于block的申请,同样block不回收,等pool销毁的时候直接归还给操作系统。这个内存池的方案,有apr_pool中block不能回收到pool的缺点,没有pool回收到allocator,以供下次继续使用的优点,不支持多线程。适合于单线程,集中使用内存的场景,意义不是很大。

posted on 2008-02-18 16:55 cppexplore 阅读(9558) 评论(17) 编辑 收藏 引用

相关文章: