2.4 内存池
2.4.1内存池概述
在了解了内存分配子的概念之后,我们其实已经了解了Apache中内存分配的细节了。不过Apache中内存的层次结构关系则是由内存池负责组织,其数据结构apr_pool_t定义在apr_pools.c中,定义如下:
struct apr_pool_t {
apr_pool_t *parent;
apr_pool_t *child;
apr_pool_t *sibling;
apr_pool_t **ref; //用于指向内存池本身
cleanup_t *cleanups;
apr_allocator_t *allocator;
struct process_chain *subprocesses;
apr_abortfunc_t abort_fn;
apr_hash_t *user_data;
const char *tag;
#if !APR_POOL_DEBUG
apr_memnode_t *active;
apr_memnode_t *self; /* The node containing the pool itself */
char *self_first_avail;
#else /* APR_POOL_DEBUG */
debug_node_t *nodes;
const char *file_line;
apr_uint32_t creation_flags;
unsigned int stat_alloc;
unsigned int stat_total_alloc;
unsigned int stat_clear;
#if APR_HAS_THREADS
apr_os_thread_t owner;
apr_thread_mutex_t *mutex;
#endif /* APR_HAS_THREADS */
#endif /* APR_POOL_DEBUG */
#ifdef NETWARE
apr_os_proc_t owner_proc;
#endif /* defined(NETWARE) */
};
Apache中存在的内存池个数通常多于一个,它们之间形成树型层次结构。每个内存池所存储的内容以及其存储周期都不一样,比如连接内存池在整个HTTP连接期间存在,一旦连接结束,内存池也就被释放;请求内存池则周期要相对短,它仅仅在某个请求周期内存存在,一旦请求结束,请求内存池也就释放。不过每个内存池都具有一个apr_pool_t结构。
整个内存池层次树通过parent、child以及sibling三个变量构建起来。parent指向当前内存池的父内存池;child指向当前内存池的子内存池;而sibing则指向当前内存池的兄弟内存池。因此整个内存池树结构可以用图3.3描述:
图3.3 内存池层次树结构图
在上面的图中,我们只是表示了层次结构,因此只是用了child和sibling两个成员,而忽略的parent的变量。从上面的图中我们可以看出根结点具有n个孩子结点:child1,child2,child3…childn。而child1,child2,child3以及childn它们属于同一个父亲,而且处于层次树的同一层次,因此它们通过链表连接,互为兄弟结点。同样child10和child11都是child1的子内存池结点,互为兄弟结点。child21是child2的唯一的子结点。其余结点类似。
除此之外apr_pool_t结构中最重要的成员变量无非就是active了。
图3.4
Apache中提供了大量的内存池管理函数,它们的功能和名称归纳在表格3.2中。
内存池操作
|
函数名称
|
函数功能简单描述
|
初始化
|
apr_pool_initialize
|
对内存池使用中需要的内部变量进行初始化
|
销毁
|
apr_pool_terminate
|
主要在终止内存池使用时销毁内部的结构
|
创建
|
apr_pool_create_ex
apr_pool_create_ex_debug
|
创建一个新的内存池,另外还包括一个调试版本
|
清除
|
apr_pool_clear
apr_pool_clear_debug
|
清除内存池中的所有的内存,另外包括一个调试版本
|
|
apr_pool_destroy
|
|
2.4.2内存池的初始化
内存池的初始化是通过函数apr_pool_initialize实现的,在内部函数完成了下面几件事情:
APR_DECLARE(apr_status_t) apr_pool_initialize(void)
{
apr_status_t rv;
if (apr_pools_initialized++)
return APR_SUCCESS;
(1)、确保Apache中只创建一个全局内存池,为此,Apache中使用apr_pools_initialized进行记录。apr_pools_initialized初始值为0,初始化后该值更改为1。每次初始化之前都检查该值,只有值为0的时候才允许继续执行初始化操作,否则直接返回。通过这种手段可以确保只有一个全局内存池存在。
if ((rv = apr_allocator_create(&global_allocator)) != APR_SUCCESS) {
apr_pools_initialized = 0;
return rv;
}
if ((rv = apr_pool_create_ex(&global_pool, NULL, NULL,
global_allocator)) != APR_SUCCESS) {
apr_allocator_destroy(global_allocator);
global_allocator = NULL;
apr_pools_initialized = 0;
return rv;
}
apr_pool_tag(global_pool, "apr_global_pool");
(2)、创建了全局的分配子global_allocator,并使用全局分配子global_allocator创建了全局内存池global_pool,该内存池是所有的内存池的祖先。所有的内存池都从该内存池继承而来。它在整个Apache的生存周期都存在,即使重启机器,该内存池也不会释放。除非你把Apache彻底关闭。该内存池在系统中命名为“apr_gloabl_pool”。
if ((rv = apr_atomic_init(global_pool)) != APR_SUCCESS) {
return rv;
}
#if APR_HAS_THREADS
{
apr_thread_mutex_t *mutex;
if ((rv = apr_thread_mutex_create(&mutex,APR_THREAD_MUTEX_DEFAULT,global_pool)) != APR_SUCCESS) {
return rv;
}
apr_allocator_mutex_set(global_allocator, mutex);
}
#endif /* APR_HAS_THREADS */
apr_allocator_owner_set(global_allocator, global_pool);
(3)、如果当前的操作系统允许多线程,为了确保内存池结构被多线程访问的时候的线程安全性,还必须设置apr_pool_t结构内的互斥锁变量mutex。最后的任务就是将内存分配子和内存池进行关联。
关于作者
张中庆,目前主要的研究方向是嵌入式浏览器,移动中间件以及大规模服务器设计。目前正在进行Apache的源代码分析,计划出版《Apache源代码全景分析》上下册。Apache系列文章为本书的草案部分,对Apache感兴趣的朋友可以通过flydish at sina.com.cn与之联系!
如果你觉得本文不错,请点击文后的“推荐本文”链接!!
分享到:
相关推荐
### Apache内存池内幕 #### 内存管理的重要性与挑战 在C语言编程中,内存管理一向被视为技术领域的一座难攻堡垒,尤其是对于像Apache这样的高性能服务器软件,内存管理的效率直接影响到系统的稳定性和响应速度。...
4. **子内存池** 内存池支持嵌套结构,可以创建子内存池。子内存池继承了父内存池的所有资源,并且可以有自己的内存块。当子内存池被销毁时,它所分配的内存将被回收,而父内存池仍然保持不变。这种方式允许模块化...
APACHE内存池概述.pdf
本资源包含Apache服务器的源码、源码分析以及内存池内幕的详细文档,是研究Apache内部机制的理想资料。 首先,Apache服务器源码分析是一个深度学习过程,它涵盖了网络协议处理、模块化架构、多线程模型、请求处理...
4. 子内存池:除了根内存池,还可以创建子内存池(`apr_pool_create_ex`或`apr_pool_create_unmanaged`)。子内存池继承父内存池的资源,并在其上添加自己的内存分配。当子内存池被销毁时,它所分配的所有内存都会被...
4. **子内存池**:除了主内存池,还可以创建子内存池。子内存池继承自父内存池,当子内存池被销毁时,其内部的所有分配都会自动回滚到父内存池,简化了内存管理的复杂性。 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中内存池的设计原理及其在实际运行过程中的...
4. **初始化连接池**:在Java程序中,我们通常使用`BasicDataSource`类来初始化和获取数据库连接。例如: ```java BasicDataSource ds = new BasicDataSource(); ds.setUrl("jdbc:mysql://localhost:3306/mydb");...
具体而言,APR为Apache提供了内存池管理功能,使得开发人员可以专注于应用逻辑,而无需过多关心底层内存细节。 #### 内存池实现 内存池的实现基于`apr_pool_t`结构体。每一个`apr_pool_t`实例代表了一个独立的内存...
apache kafka技术内幕 和 apacke kafka源码分析2本PDF 电子书 网盘下载