您的位置:首页 > 运维架构 > Apache

Apache内存池使用过程的分析

2015-11-29 14:15 531 查看
毫无疑问,内存池使用的总的流程是:首先创建一个内存池,在创建的过程中指定它的父内存池,并需要将其挂接到对应的内存池树层次结构上;其次,使用内存池,刚开始使用时内存池中除了本身结点的一点空间外,没有其他的空间了,如果需要的内存较大,则需要从分配子中分配内存,并挂接到内存池的active 链表上,然后直接使用;最后,内存池的销毁,内存池的销毁同时内存也都会重新释放到分配子中,由分配子进行管理。
下面从整个过程详细介绍一下内存的全流程使用,主要是以Apache的main函数中对内存的使用为例。
(1)apr_pool_create函数
main函数中最开始涉及到内存使用的地方在init_process函数中,在函数中,使用内存时,调用的便是apr_pool_create(&cntx, NULL),以此创建第一个全局内存池cntx,我们来看apr_pool_create函数的工作过程:
apr_pool_create实际调用的是apr_pool_create_ex函数来创建,继续往下,
1.首先判断创建的内存池有没有设定父内存池,如果没有则默认的将其设置为其父内存池为根内存池,即全局内存池。
2.然后,函数首先创建apr_pool_t结构,其方法是首先通过分配子分配一个最小内存空间为8K的内存结点,然后将apr_pool_t结构放在apr_memnode_t结构的下面,并对各个字段初始化。结构如下:



 3.接着,如果父内存池一开始是通过默认设置的,这时会有parent == NULL,也就是说此时创建的内存池将作为根内存池,否则就作为parent的子内存池。
内存池创建的详细过程可以参考tinya的博客。

(2)apr_palloc函数
在实际使用中,若需要分配内存空间,则需要向内存池申请使用。内存池内存分配的两个函数为apr_palloc和apr_pcalloc函数,实际上apr_pcalloc函数也是通过apr_palloc函数来实现的,下面来分析该函数:
内存池的结构中有一个active链表,它是实际内存所在的地方。首先判断active链表上的空间是否满足要求,它是通过比较size和node_free_space(active)来判断的,node_free_space是结点中实际可用的空间大小;如果active链表没有满足要求的空间,则需要从分配子中进行分配,分配的结点需要插入到active链表中的合适位置上去。总的来说,不论哪种情况,mem指向结点可用的空间,并调整结点的字段first_avail,这两步操作是通过程序中以下两行代码实现:
mem = node->first_avail;
node->first_avail += size;
也就是说,程序用到的内存都在active链表上,并且将结点字段first_avail向下移动,表明以上空间已被使用了。
看到这里的时候,我在想如果程序需要释放该内存时,是不是会把first_avail字段往上调,但是我从内存池销毁函数中始终没有找到这方面的信息。

(3)apr_pool_terminate, apr_pool_clear, apr_pool_destroy
Apache应用程序中需要用到的内存都是从内存池分配的,使用时只需调整对应结点的first_avail字段,而并不会从active链表上取出,因为该结点可能还有剩余空间没有使用,这样如果还有程序需要使用内存的话,该结点仍然可以使用的一个选择(当然这里面涉及到active链表的重新排序)。
Apache源程序中,apr_pool_clear 、apr_pool_terminate等函数最终都是通过apr_pool_destroy函数实现的,函数中如果要销毁一个内存池,首先得通过递归的方法把它的子内存池释放掉,才能对该内存池进行释放。函数中都有这样一段代码可以证明:
while ( pool->child)
    apr_pool_destroy(pool->child)

因此,可以推断:在内存池释放或销毁前,active不会被销毁,并且内存不够用时会向分配子要求分配所需空间,active链表上的结点所含的可用空间只会越来越少,即first_avail字段只会往下调,只有当内存池销毁时,active链表的内存才会释放给分配子。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: