分类:
2005-10-13 15:14:09
几乎每一个使用过C语言的开发者曾经感叹令人畏缩的内存管理,分配足够的内存,并且追踪内存的分配,在不需要时释放内存—这个任务会非常复杂。当然,如果没有正确地做到这一点会导致程序毁掉自己,或者更加严重一点,把电脑搞瘫。幸运的是,Subversion所依赖的APR库为了可携带型提供了apr_pool_t类型,代表了应用可以分配内存的池。
一个内存池是程序所需要分配内存的一个抽象表示,不选择使用标准的malloc()
从操作系统直接申请内存,而使用向APR申请的池申请创建的(使用apr_pool_create()
方法)内存。APR会从操作系统分配合适的内存块这些内存可以立刻在程序里使用,当程序需要更多的池内存时,它会使用APR的池API方法,如apr_palloc()
,返回池中的基本内存位置,这个程序可以继续从池中请求内存,在超过最初的池的容量后,APR会自动满足程序的要求扩大池的大小,直到系统没有足够的内存。
现在,如果这是池故事的结尾,我们就不应该再作过多的关注,很幸运,不是这个情况。池不可以仅仅被创建;它也可以被清空和销毁,分别使用apr_pool_clear()
和apr_pool_destroy()
。这给了用户灵活性来分配许多—或者是数千—东西自这个池,然后使用一个命令来清空!更进一步,池由登记,你可以为前一步创建的池创建“子池”。当你清空一个池,所有的子池会被销毁;如果你销毁一个池,它和所有的子池也会被销毁。
在我们进一步研究之前,开发者会发现在Subversion源代码中并没有对前面提到的APR池方法有很多的调用,APR提供了许多扩展机制,像使用自定义的附加到池的“用户数据”的能力,注册当池销毁时的所要调用的清理方法的机制,Subversion使用一些不太琐碎的方法来利用这些扩展,所以Subversion提供了(大多数代码使用的)包裹方法svn_pool_create()
、svn_pool_clear()
和svn_pool_destroy()
。
尽管池帮助我们基本的内存管理,池的创建确实投射出了循环和迭代场景,因为反复在循环中经常没有界限,在深度迭代中,一定区域的内存消耗变得不可预料,很幸运,使用嵌套的内存池可以简单的管理这种潜在的混乱情形,下面的例子描述了在这个情形下嵌套池的基本使用非常平常—迭代的对目录树的遍历,对树上的每一个部分做一些人物。
在前一个例子里描述了在循环和迭代情况下有效地池使用,每次迭代会从为传递给池的建立一个子池开始,池在循环区域中使用在每次迭代清理。结果是内存使用比例和深度成比例,而不是顶级目录包含所有的子目录的总数量。当迭代的第一个调用最终结束时,实际上只有很小的传递过来的数据存放在池中,现在想想一下如果在每片数据使用时使用alloc()
和free()
时会面临的复杂性!
池并不是对所有的应用是理想的,但是在Subversion中非常有用,作为一个Subversion开发者,你会需要学会适应池并且正确地使用它,内存使用的bug和膨胀可能会非常难于诊断和修正,但是APR提供的pool结构被证明了是非常的方便的,节约时间的功能。