2.4.3内存池的创建
勿庸置疑,内存池的创建是内存池的核心操作之一。内存池创建函数的原型如下所示:
APR_DECLARE(apr_status_t) apr_pool_create_ex(apr_pool_t **newpool,
apr_pool_t *parent,
apr_abortfunc_t abort_fn,
apr_allocator_t *allocator)
其中,newpool是需要创建的新的内存池,并且创建后的内存池通过该参数返回。parent则是当前创建的内存池的父亲;abort_fn指明了当创建失败的时候所调用的处理函数;allocator则是真正进行内存分配的分配子。
{
apr_pool_t *pool;
apr_memnode_t *node;
*newpool = NULL;
if (!parent)
parent = global_pool;
if (!abort_fn && parent)
abort_fn = parent->abort_fn;
if (allocator == NULL)
allocator = parent->allocator;
在创建过程中,我们没有指定当前创建的内存池的父亲,则将其默认为父亲为根内存池global_pool,同时如果内存池关联的abort_fn和分配子allocator没有定义,那么也直接继承父辈的相关信息。
if ((node = allocator_alloc(allocator,MIN_ALLOC - APR_MEMNODE_T_SIZE)) == NULL) {
if (abort_fn)
abort_fn(APR_ENOMEM);
return APR_ENOMEM;
}
node->next = node;
node->ref = &node->next;
pool = (apr_pool_t *)node->first_avail;
node->first_avail = pool->self_first_avail = (char *)pool + SIZEOF_POOL_T;
pool->allocator = allocator;
pool->active = pool->self = node;
pool->abort_fn = abort_fn;
pool->child = NULL;
pool->cleanups = NULL;
pool->free_cleanups = NULL;
pool->subprocesses = NULL;
pool->user_data = NULL;
pool->tag = NULL;
在一切就绪之后,函数将必须首先创建apr_pool_t结构。但是前面我们曾经说过Apache中对所有内存的分配都是以内存结点apr_memnode_t进行分配的,而且每次分配的最小单元为8K,这对于创建apr_pool_t结构也不例外。因此函数将首先调用分配子allocator分配8K的内存,然后将最顶端的内存分配给apr_memnode_t结构。此时接着apr_memnode_t结构下面的内存才能继续分配给apr_pool_t,用来表示内存池结构,apr_pool_t结构之后才是真正可用的空间。在整个8K内存中,结点头和内存池头部分别占用的空间大小为APR_MEMNODE_T_SIZE和SIZEOF_POOL_T,因此用户真正可用的空间实际上只有(8k-APR_MEMNODE_T_SIZE-SIZEOF_POOL_T)大小了,至此我们还必须要调整apr_memnode_t中的first_avail指针和apr_pool_t结构中的self_first_avail指针指向真正可用空间。
经过两轮分配之后,8K内存的布局如图3.5所示:
<shapetype id="_x0000_t75" coordsize="21600,21600" o:spt="75" o:preferrelative="t" path="m@4@5l@4@11@9@11@9@5xe" filled="f" stroked="f"><img alt="" src="http://asp.6to23.com/vcprogram/image/memorylayout.png"><br></shapetype>
一旦完成了内存池结点的分配工作,我们必须将其挂结到内存池层次树上。挂结的过程无非就是设置parent,child以及sibling的过程。
if ((pool->parent = parent) != NULL) {
if ((pool->sibling = parent->child) != NULL)
pool->sibling->ref = &pool->sibling;
parent->child = pool;
pool->ref = &parent->child;
}
else {
pool->sibling = NULL;
pool->ref = NULL;
}
*newpool = pool;
挂结的过程可以分为下面几个步骤:
(1)、将当前的结点的parent指针指向父结点,即pool->parent = parent。
(2)、设定当前结点的sibing。sibing应该指向那些与当前结点处于同一层次,并且父结点也相同的结点,新的结点总是被插入到子结点链表的首部,插入通过下面的两句实现:
pool->sibling = parent->child;
parent->child = pool;
不过如果父结点为空,意味着该结点未有兄弟结点,故pool->sibling = NULL。
(3)、设置ref成员。在apr_pool_t中,ref用于指向
在内存池结点创建的过程中,我们可以看到,内存池创建后active仍然为空。因此当前内存池中能够被使用的内存仅仅为8k- APR_MEMNODE_T_SIZE-SIZEOF_POOL_T大小。如果用户从内存池中申请更多的内存的时候,很明显,此时必须通过active去扩展该内存池对应的内存结点。这一点我们可以在内存池的内存分配中看出来。
关于作者
张中庆,目前主要的研究方向是嵌入式浏览器,移动中间件以及大规模服务器设计。目前正在进行Apache的源代码分析,计划出版《Apache源代码全景分析》上下册。Apache系列文章为本书的草案部分,对Apache感兴趣的朋友可以通过flydish at sina.com.cn与之联系!
如果你觉得本文不错,请点击文后的“推荐本文”链接!!
<shapetype id="_x0000_t75" coordsize="21600,21600" o:spt="75" o:preferrelative="t" path="m@4@5l@4@11@9@11@9@5xe" filled="f" stroked="f"><stroke joinstyle="miter"></stroke><formulas><f eqn="if lineDrawn pixelLineWidth 0"></f><f eqn="sum @0 1 0"></f><f eqn="sum 0 0 @1"></f><f eqn="prod @2 1 2"></f><f eqn="prod @3 21600 pixelWidth"></f><f eqn="prod @3 21600 pixelHeight"></f><f eqn="sum @0 0 1"></f><f eqn="prod @6 1 2"></f><f eqn="prod @7 21600 pixelWidth"></f><f eqn="sum @8 21600 0"></f><f eqn="prod @7 21600 pixelHeight"></f><f eqn="sum @10 21600 0"></f></formulas><path o:extrusionok="f" gradientshapeok="t" o:connecttype="rect"></path><lock v:ext="edit" aspectratio="t"></lock></shapetype><shape id="_x0000_i1025" style="WIDTH: 237pt; HEIGHT: 209.25pt" type="#_x0000_t75"><imagedata src="file:///C:%5CDOCUME~1%5CADMINI~1%5CLOCALS~1%5CTemp%5Cmsohtml1%5C01%5Cclip_image001.png" o:title=""></imagedata></shape>
分享到:
相关推荐
### Apache内存池内幕 #### 内存管理的重要性与挑战 在C语言编程中,内存管理一向被视为技术领域的一座难攻堡垒,尤其是对于像Apache这样的高性能服务器软件,内存管理的效率直接影响到系统的稳定性和响应速度。...
5. **内存池的优点** - **减少碎片**:由于内存池一次性分配大量内存,避免了小块内存分配造成的碎片。 - **提高效率**:内存池的分配和回收操作比系统级别的malloc/free快。 - **易于管理**:统一的内存回收机制...
APACHE内存池概述.pdf
本资源包含Apache服务器的源码、源码分析以及内存池内幕的详细文档,是研究Apache内部机制的理想资料。 首先,Apache服务器源码分析是一个深度学习过程,它涵盖了网络协议处理、模块化架构、多线程模型、请求处理...
总的来说,Apache APR的内存池是其底层实现的关键组成部分,对于理解和优化Apache服务器的性能至关重要。开发者在使用APR进行开发时,应熟练掌握内存池的使用方法,以便更好地控制和管理内存资源。通过合理使用内存...
APR内存池,全称Apache Portable Runtime(阿帕奇可移植运行时)内存池,是阿帕奇HTTP服务器项目中的一个重要组成部分,它提供了一种高效、便捷的内存管理机制。在设计之初,APR内存池的目标是为跨平台的系统编程...
这种内存池结合了Apache内存池和固定块内存池的优点,实现了快速的内存分配和回收,同时减少了内存碎片。 #### 三、SVBSMP的设计原理 ##### 1. 结构设计 SVBSMP主要包括两种结构: - **内存块(Mem Block)**: 这...
### Apache服务器出现内存溢出的解决方法 #### 知识点概述 本文主要探讨了Apache服务器在运行过程中遇到内存溢出问题的几种常见情况及其解决办法。虽然标题提及的是Apache服务器,但文中实际讨论的是与Apache...
此脚本可以计算出当前httpd进程的个数和占用内存,来为我们配置apache工作模式提供参考
Apache对象池技术是一种高效利用资源的策略,它通过预先创建并维护一组可重用对象来减少频繁创建和销毁对象带来的开销。在Java环境中,Apache Commons Pool库是实现对象池的常见工具,它提供了多种对象池实现,适用...
### Apache源代码内核分析——内存池管理机制详解 #### 一、引言 Apache作为全球广泛使用的Web服务器软件之一,其稳定性和高效性在很大程度上依赖于良好的内存管理机制。尤其是在高并发环境下,如何有效地管理和...
Apache的内存管理方案通过以上机制,将内存池作为整个APR(Apache Portable Runtime)的基础,确保了程序在运行过程中内存的高效分配与管理。学习和掌握Apache内存池的工作原理,对进阶成为一名优秀的架构师是十分有...
### Apache源代码全景分析——内存池机制深度剖析 #### 一、引言 Apache作为一款高性能的Web服务器软件,其内部实现中一个重要的组件便是内存池。本文将深入探讨Apache中内存池的设计原理及其在实际运行过程中的...
5. **使用连接池**:获取数据库连接时,调用`getConnection()`方法: ```java Connection conn = ds.getConnection(); // 执行SQL语句... conn.close(); // 归还连接到池,而不是真正关闭 ``` 6. **连接池管理...
具体而言,APR为Apache提供了内存池管理功能,使得开发人员可以专注于应用逻辑,而无需过多关心底层内存细节。 #### 内存池实现 内存池的实现基于`apr_pool_t`结构体。每一个`apr_pool_t`实例代表了一个独立的内存...
apache kafka技术内幕 和 apacke kafka源码分析2本PDF 电子书 网盘下载