2.4.4内存池的内存分配
从内存池中分配内存通过两个函数实现:apr_pcalloc和apr_palloc,这两个函数唯一的区别就是apr_pcalloc分配后的内存全部自动清零,而apr_palloc则省去了这一步的工作。
apr_palloc的函数原型如下所示:
APR_DECLARE (void *) apr_palloc (apr_pool_t *pool, apr_size_t size)
函数中pool是需要分配内存的内存池,size则是需要分配的内存的大小。一旦分配成功则返回分配内存的地址。
在了解内存池的内存分配之前,我们应该对active链表有所了解。顾名思义,active链表中保存的都是曾经被使用或者正在被使用的apr_memnode_t内存结点。这些结点都是由分配子进行分配,之所以被使用,一个重要的原因就是它们有足够空闲的空间。将这些结点保存在active上,这样下次需要内存的时候只要首先遍历active链表即可,只有在active链表中的结点不能够满足分配要求的时候才会重新跟分配子申请新的内存。另一方面,一旦某个结点被选中进入active链表,那么它就不能在原先的分配子链表中存在。
对于每一个apr_memnode_t内存结点,它的实际可用空间为endp-first_avail的大小。但是正如前面所说,Apache中衡量空间通常使用索引的方法,对于所有的结点,它的空闲空间用free_index描述。为了加快查找速度,active链表中的所有的结点按照其空间空间的大小进行反向排序,为此空闲空间大得总是排在前面,空闲空间最小的则肯定排在最末尾。对于指定的分配空间,只要将其与第一个结点的空闲空间进行比较,如果第一个空闲都不满足,那么此时必须向分配子重新申请空间,否则直接从第一个结点中分配空间,同时调整分配后的结点次序。
apr_memnode_t *active, *node;
void *mem;
apr_size_t free_index;
size = APR_ALIGN_DEFAULT(size);
active = pool->active;
if (size < (apr_size_t)(active->endp - active->first_avail)) {
mem = active->first_avail;
active->first_avail += size;
return mem;
}
分配首先计算需要分配的实际空间,这些空间都是使用对齐算法调整过的。Apache首先尝试到active链表的第一个结点中去分配空间,正如前面所言,这个是链表中空闲最多的结点,如果它能够满足需要,Apache直接返回size大小的空间,同时调整新的first_avail指针。不过这里需要注意的是对于空链表的情况。当一个内存池使用apr_create_pool_ex新创建以后,它的active链表为空,不过此时active并不为NULL,事实上active=node,意味着active指向内存池所在的内存结点。因此这种情况下,空间的分配并不会失败。
node = active->next;
if (size < (apr_size_t)(node->endp - node->first_avail)) {
list_remove(node);
}
else {
if ((node = allocator_alloc(pool->allocator, size)) == NULL) {
if (pool->abort_fn)
pool->abort_fn(APR_ENOMEM);
return NULL;
}
}
如果active链表中的结点都不能满足分配需求,那么此时唯一能够做的就是直接向分配子申请更多的空间。至于分配子如何去分配,是从池中获取还是直接调用malloc分配,此处不再讨论。
node->free_index = 0;
mem = node->first_avail;
node->first_avail += size;
list_insert(node, active);
pool->active = node;
free_index = (APR_ALIGN(active->endp - active->first_avail + 1,
BOUNDARY_SIZE) - BOUNDARY_SIZE) >> BOUNDARY_INDEX;
active->free_index = (APR_UINT32_TRUNC_CAST)free_index;
node = active->next;
if (free_index >= node->free_index)
return mem;
一旦获取到分配的新的结点,那么下一步就是从该结点中分配需要的size大小的空间,由mem指针指向该空间首地址。同时将该结点立即插入到actie链表中作为首结点。插入通过宏list_insert实现:
#define list_insert(node, point) do { \
node->ref = point->ref; \
*node->ref = node; \
node->next = point; \
point->ref = &node->next; \
} while (0)
前面我们说过,active链表的第一个结点肯定是空闲空间最大的结点。尽管从池中刚分配的时候,node结点的空闲空间确实是最大,但是一旦分配了size大小之后则情况未必,因此node作为第一个结点存在可能是不合适的,为此必须进行适当的调整。
1)、如果新插入结点node的空闲空间确实比后继结点node->next的空间大,那么此时,毫无疑问,node是所有结点中空闲空间最大的结点,物归其所,不需要再调整。
do {
node = node->next;
}
while (free_index < node->free_index);
list_remove(active);
list_insert(active, node);
2)、如果node的空间比node->next的空间小,那么意味着node放错了地方,为此必须从node->next开始往后遍历找到合适的位置,并从原位置移出,插入新位置。
关于作者
张中庆,目前主要的研究方向是嵌入式浏览器,移动中间件以及大规模服务器设计。目前正在进行Apache的源代码分析,计划出版《Apache源代码全景分析》上下册。Apache系列文章为本书的草案部分,对Apache感兴趣的朋友可以通过flydish at sina.com.cn与之联系!
如果你觉得本文不错,请点击文后的“推荐本文”链接!!
分享到:
相关推荐
### Apache内存池内幕 #### 内存管理的重要性与挑战 在C语言编程中,内存管理一向被视为技术领域的一座难攻堡垒,尤其是对于像Apache这样的高性能服务器软件,内存管理的效率直接影响到系统的稳定性和响应速度。...
6. **内存池的限制** - **内存浪费**:如果内存池分配过大,但实际使用较少,可能会造成内存浪费。 - **不可预测的内存增长**:内存池会根据需要动态扩展,但其增长情况对用户来说可能是不可预测的。 总结,...
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中内存池的设计原理及其在实际运行过程中的...
6. **连接池管理**:DBCP提供了监控和调整连接池大小的功能,比如当连接池耗尽时,可以根据预设策略自动扩展;当空闲连接过多时,可以自动回收。 7. **优点**:使用数据库连接池可以提高性能,因为创建和销毁连接是...
具体而言,APR为Apache提供了内存池管理功能,使得开发人员可以专注于应用逻辑,而无需过多关心底层内存细节。 #### 内存池实现 内存池的实现基于`apr_pool_t`结构体。每一个`apr_pool_t`实例代表了一个独立的内存...
apache kafka技术内幕 和 apacke kafka源码分析2本PDF 电子书 网盘下载