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链表的内存才会释放给分配子。
下面从整个过程详细介绍一下内存的全流程使用,主要是以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链表的内存才会释放给分配子。
相关文章推荐
- Java日志学习三:Apache Log4j源码浅析
- Java日志学习二:Apache Commons Logging (JCL)源码
- 使用ApacheBench对网站进行压力测试
- Unclean shutdown of previous Apache run问题处理
- Mac Os X Yosemite 10.10.5 配置apache,php,mysql
- Apache Stratos探究:Apache Stratos 4.1.x 的架构
- apache Storm学习之三-消息可靠性
- apache服务器的效率 可以体现出当今世界的科技一角
- apache配置常用模块
- [转]mac 10.9.4下配置apache
- php在apache中运行模式
- apache Storm学习之二-基本概念介绍
- build maven项目时出现错误noclassdeffounderror:org/apache/tools/ant/DefaultLogger
- Apache的配置
- 阿里云服务器配置php+apache+mysql+phpMyadmin开发环境并上传本地代码
- Apache Commons-SCXML系列之"HelloWorld"
- Yarn模式下Apache HAWQ的运行 [作者:白洁]
- Windows 的Apache支持SSI配置
- Mac OS X中配置Apache
- 利用Apache服务器屏蔽广告及IP段的一般方法