通常程序下,C语 言中内存的分配与 释 放是用 malloc与free。缺点很多, 开发 者可能因 为 疏忽而忘 记释 放。在 Apache 这样 的服 务 器中如果内存有泄漏是 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
不可被容忍的。而且频繁的malloc与free可能会造成页面错误。如果一直不释放会造成系统性能下降。 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
因此Apache引入了内存池概念。内存池是一片很大的内存空间,一次性分配成功避免反 复的申 请释放。而且内存的释放会在内存销 毁的 时候释放。 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
但如果内存池只有一个的话,那 么 这个内存池需要在Apache启动的时候申请,在Apache关闭的时候释放。这样显得不太合理。 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
因此Apache会使用多个内存池,采用分级的方法, 每一 级内存池的生命周期不同。 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
首先,我需要了解一下Apache代码的结构: | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
apache可划分为四大层次:可移植运行库( APR)、核心功能 层( Apache CORE)、可 选功能层( Apache Optional Module)、第三方支持 库。 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
图例: | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Apche模块 中的第三方支持 库 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
OpenSSL PHP …………………………………………………………………Perl LDAP | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Apche可选 功能 层 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
mod_SSL mod_Php mod_rewrite ………………………………………mod_perl mod_ladp | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Apche核心功能层 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
http_core http_request……http_protocol(Apache核心) mod_so core MPM http(核心模块) | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
libapr库 (可移 值 运行 库层 ) | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
共享内存 文件I/O 网络 I/O…… libpcre libldap libexpat | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
操作系统 (Win32、Unix、OS/2、MacOS、Netware) | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
因为OS不同,apache在处理跨平台的时候显然需要使用不同的系统API。从2.0开始,Apache将专门封装不同操作系统API的任务分离了出来,形成APR。 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
这样对于所有的操作系统,提供了一个完全相同的函数接口。这样事实上,任何应用程序想要跨平台均可使用APR做为底层的支持。 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
其次,我需要了解一下内存池的分级情况: | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
但需要注意的是pool并不会直接分配与释放内存,而是通过 allocator来 统一管理。 Pool采用的是 树形结构,如上图所示。在内存初始化时,使用函数 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
apr_pool_initialize建立根池与全局的allocator,以后建立的都是根结点的子孙结点。可以从 pool中分配任何大小的内存。但需要在 释放 pool 时这些申请的内存 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
才会被释放。需要注意 的是,有些分配的内存块,清除时有特别的操作,所以需要自带清除函数,在分配之后用apr_pool_cleanup_register注册清除时用的 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
函数。特殊的是,如果内存块里是线程对象,不能用一般的清除函数,应该用apr_pool_note_subprocess注册清除操作。 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
接下来,需要看一下池的结 构:(以下内容,摘自http://blog.youkuaiyun.com/fastxyf/archive/2006/06/30/855344.aspx)需要 亲自对代码中看一下。 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
//池的结 构 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
struct apr_pool_t { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
apr_pool_t *parent; //父池结 点 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
apr_pool_t *child; //子池结 点 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
apr_pool_t *sibling; //兄弟池结 点 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
apr_pool_t **ref; //指向-指向自已的指针 ,一般是前 继结 点的next指 针 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
cleanup_t *cleanups; //需要清除函数来销 毁 的内存 块 指 针 列表,通 过 注册来加入的 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
cleanup_t *free_cleanups;//当Kill 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 */ | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
apr_pool_t *joined; /* the caller has guaranteed that this pool | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
* will survive as long as ->joined */ | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
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) */ | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}; | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
相关的函数: | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
[函数] | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
对系 统 内存池初始化,全局的,一个 进 程只要初始化一次 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
apr_status_t apr_pool_initialize (void) | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
销毁 内存池 对 象,及内部的 结 构和子内存池 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
void apr_pool_terminate (void) | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
创建一个新的内存池 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
apr_status_t apr_pool_create_ex (apr_pool_t **newpool, apr_pool_t *parent, apr_abortfunc_t abort_fn, apr_allocator_t *allocator) | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
创建一个新的内存池,apr_pool_create_ex的使用默 认 参数 简 化版 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
apr_status_t apr_pool_create (apr_pool_t **newpool, apr_pool_t *parent) | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
获取内存池使用的内存分配器 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
apr_allocator_t * apr_pool_allocator_get (apr_pool_t *pool) | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
清除一个内存池的内容,清除后内容为 空,但可以再使用 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
void apr_pool_clear (apr_pool_t *p) | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
释构一个内存池 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
void apr_pool_destroy (apr_pool_t *p) | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
从池中分配内存 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
void * apr_palloc (apr_pool_t *p, apr_size_t size) | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
从池中分配内存,并将分配出来的内存置0 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
void * apr_pcalloc (apr_pool_t *p, apr_size_t size) | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
设置内存分配出 错时 的 调 用函数 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
void apr_pool_abort_set (apr_abortfunc_t abortfunc, apr_pool_t *pool) | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
获取内存分配出 错时 的 调 用函数 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
apr_abortfunc_t apr_pool_abort_get (apr_pool_t *pool) | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
获取池的父池 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
apr_pool_t * apr_pool_parent_get (apr_pool_t *pool) | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
判断a是否是b的祖先 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
int apr_pool_is_ancestor (apr_pool_t *a, apr_pool_t *b) | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
为内存池做 标签 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
void apr_pool_tag (apr_pool_t *pool, const char *tag) | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
设置与当前池 关联 的数据 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
apr_status_t apr_pool_userdata_set (const void *data, const char *key, apr_status_t(*cleanup)(void *), apr_pool_t *pool) | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
设置与当前池 关联 的数据,与apr_pool_userdata_set 类 似,但内部不拷 贝 数据的 备 份,如常量字符串 时 就有用 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
apr_status_t apr_pool_userdata_setn (const void *data, const char *key, apr_status_t(*cleanup)(void *), apr_pool_t *pool) | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
获取与当前池 关联 的数据 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
apr_status_t apr_pool_userdata_get (void **data, const char *key, apr_pool_t *pool) | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
注册内存块 的清除函数, 每 块销 毁 时 要特 别处 理的都要注册下,在cleanups里加入一个 项 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
void apr_pool_cleanup_register (apr_pool_t *p, const void *data, apr_status_t(*plain_cleanup)(void *), apr_status_t(*child_cleanup)(void *)) | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
删除内存 块 的清除函数,从cleanups里移除一个 项 ,放入free_cleanups中 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
void apr_pool_cleanup_kill (apr_pool_t *p, const void *data, apr_status_t(*cleanup)(void *)) | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
用新的child_cleanup,替换 原来老的child_cleanup | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
void apr_pool_child_cleanup_set (apr_pool_t *p, const void *data, apr_status_t(*plain_cleanup)(void *), apr_status_t(*child_cleanup)(void *)) | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
执行内存 块 的清除函数, 进 从清除函数的 队 列cleanups中 删 除 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
apr_status_t apr_pool_cleanup_run (apr_pool_t *p, void *data, apr_status_t(*cleanup)(void *)) | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
一个空的内存块 清除函数 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
apr_status_t apr_pool_cleanup_null (void *data) | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
执行所有的子清除函数child_cleanup | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
void apr_pool_cleanup_for_exec (void) | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
带调试信息内存池函数,功能跟上面的一 样 ,只是多了 调试 信息 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
apr_status_t apr_pool_create_ex_debug (apr_pool_t **newpool, apr_pool_t *parent, apr_abortfunc_t abort_fn, apr_allocator_t *allocator, const char *file_line) | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
void apr_pool_clear_debug (apr_pool_t *p, const char *file_line) | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
void apr_pool_destroy_debug (apr_pool_t *p, const char *file_line) | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
void * apr_palloc_debug (apr_pool_t *p, apr_size_t size, const char *file_line) | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
void * apr_pcalloc_debug (apr_pool_t *p, apr_size_t size, const char *file_line) | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
以下描述的应该是apache初始化内存池的一系统操作: | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
<一>内存池初始化 apr_pool_initialize | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
1.一个进 程只在第一次 调 用 时 初始化,后面只 记录调 用的次数 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if (apr_pools_initialized++) | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return APR_SUCCESS; | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
2.创 建全局内存分配器(global_allocator) | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if ((rv = apr_allocator_create(&global_allocator)) != APR_SUCCESS) { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
apr_pools_initialized = 0; | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return rv; | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
3.创 建全局内存池,根内存池 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
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; | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
4.为 内存池做 标记 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
apr_pool_tag(global_pool, "apr_global_pool"); | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
5.初始化原子操作 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
6.对 于支持多 线 程的系 统 , 还创 建互拆体,并 设 置到内存分配器 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
#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 */ | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
7.设 置内存分配器的池所有者 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
apr_allocator_owner_set(global_allocator, global_pool); | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
<二>销 毁 内存池 对 象 apr_pool_terminate | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
1.如果调 用了多次内存池初始化, 则 只有在 调 用了相 应 次数的 销 毁 时 ,最后一次才 进 行操作 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if (!apr_pools_initialized) | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return; | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if (--apr_pools_initialized) | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return; | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
2.释 放全局内存池,同 时 会 释 放想 应 的互拆体,如果内存分配器的所有者是本内存池, 则 一同 释 放内存分配器 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
apr_pool_destroy(global_pool); | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
<三>创 建一个新的内存池 apr_pool_create_ex | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
参数说 明: | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
newpool 新创 建的内存池指 针 ,用于返回的. | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
parent 父内存池. 如果为 空, 则 父内存池 为 根内存池,非空 时 ,新的内存池 继 承父内存池的属性. | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
abort_fn 分配内存失败时 的回 调 函数,中断函数 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
allocator 新内存池所用的内存分配器. NULL则 使用父内存池的内存分配器 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
1.先确定内存池的参数,如父结 点,出 错处 理函数,所用的内存分配器 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if (!parent) | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
parent = global_pool; | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if (!abort_fn && parent) | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
abort_fn = parent->abort_fn; | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if (allocator == NULL) | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
allocator = parent->allocator; | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
2.从内存分配器一块 内存 块 ,用于存 贮 内存池的信息,如果内存分配失 败 , 则调 用中断函数 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if ((node = allocator_alloc(allocator, | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
MIN_ALLOC - APR_MEMNODE_T_SIZE)) == NULL) { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if (abort_fn) | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
abort_fn(APR_ENOMEM); | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return APR_ENOMEM; | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
3.用新分配内存块 ,存 贮 内存池的 结 构apr_pool_t | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
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_memnode_t | 占用大小 APR_MEMNODE_T_SIZE | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ---------------| | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| apr_pool_t | 占用大小 SIZEOF_POOL_T | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ---------------| | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 可用空间 | 占用大小 8K - APR_MEMNODE_T_SIZE - SIZEOF_POOL_T | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ---------------| | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
4.系统 支持多 线 程, 则创 建互拆体. | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
5.设 置兄弟 结 点,及父 结 点 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if ((pool->sibling = parent->child) != NULL) | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
pool->sibling->ref = &pool->sibling; | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
parent->child = pool; | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
pool->ref = &parent->child; | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
apr_pool_create 是使用了默认 的内存分配器,和中断函数的apr_pool_create_ex 简 化版 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
#define apr_pool_create(newpool, parent) / | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
apr_pool_create_ex(newpool, parent, NULL, NULL) | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
<四> 从池中分配一块 内存 apr_palloc | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
参数说 明: | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
pool 要分配内存的池 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
size 要分配的内存大小 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
1.先按8字节对齐 size | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
size = APR_ALIGN_DEFAULT(size); | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
2. 如果首结 点有足 够 的空 闲 空 间 , 则 从 这 里分配 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if (size < (apr_size_t)(active->endp - active->first_avail)) { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
mem = active->first_avail; | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
active->first_avail += size; | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
return mem; | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
3.跟链 表首 结 点比 较 (因 为链 表 结 点是按空 闲 空 间 的大小,由多至少排序的,所以首 结 点不 够 ,后面的也不用比了),空 间够 就从 链 表 头结 点分配,因 为 分配后 链 表 头结 点空 闲 空 间 不一定 还 最多了,所以要取出,后面重新插入 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
如果链 表首 结 点空 间 不 够 , 则调 用内存分配器,新分配一 块 内存 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
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; | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
4.将首结 点或新分配的 结 点node,插到 队 列首部,再根据node里的空 间 大小, 选择 插到的位置 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
这 里没看懂, 为 什 么 要插入?到后面找又先移出,再插到正确位置.不能改成直接在后面一次插入? | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
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; | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
do { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
node = node->next; | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
while (free_index < node->free_index); | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
list_remove(active); | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
list_insert(active, node); | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
apr_pcalloc 是在apr_palloc分配的内存上,增加了对 分配的内存 块 置0 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
size = APR_ALIGN_DEFAULT(size); | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
if ((mem = apr_palloc(pool, size)) != NULL) { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
memset(mem, 0, size); | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
} | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
<五>清空池内容,释 放占用的内存,但保留池 对 象 apr_pool_clear | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
1.如果存在子池,则释 放所有子池 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
while (pool->child) | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
apr_pool_destroy(pool->child); | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
2.调 用清除函数,清除注册了 销 毁 函数的内存 块 , 每 块 需要 销 毁 函数的内存 块 都要 单 独注册 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
run_cleanups(&pool->cleanups); | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
3.清除包括子线 程的内存 块 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
free_proc_chain(pool->subprocesses); | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
4.清除附在本内存池上的内存块 ,回到 刚 分配内存池的状 态 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
*active->ref = NULL; | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
allocator_free(pool->allocator, active->next); | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
active->next = active; | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
active->ref = &active->next; | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
<六>释 构一个内存池 apr_pool_destroy | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
执 行的操作和apr_pool_clear差不多,增加了 删 除互拆体,和 释 放内存池 结 构占用的 块 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
如果所用的内存分配器的所有者,是本内存池,也一并析构 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
内存池的结构与相关函数了解了以后,应该了解一下内存结点的情况: | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
内存结点是Apache整个内存管理的基础,结构如下: | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
/** basic memory node structure */ | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
struct apr_memnode_t { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
apr_memnode_t *next; /**< next memnode */ | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
apr_memnode_t **ref; /**< reference to self */ | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
apr_uint32_t index; /**< size */ | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
apr_uint32_t free_index; /**< how much free */ | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
char *first_avail; /**< pointer to first free memory */ | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
char *endp; /**< pointer to end of free memory */ | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
}; | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
该结构中,不同的结点之间采用next指针形成结点链表。在结点内部为了方便引用自身,成员中加入的ref,主要用来记录当前结点的首地址。 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
该结构中没有存放实际分配的内存,它不会单独存在,依附于具体的内存分配单元。一旦实际内存分配后该结构置于整个单元的顶部。 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
如下图示,内存结点的情况: | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||