一 内存池的代码结构
/*****************************************************************
*
* Managing free storage blocks...
*from os.c in apache v1.3.34
*/
union align {
/* Types which are likely to have the longest RELEVANT alignment
* restrictions...
*/
char *cp;
void (*f) (void);
long l;
FILE *fp;
double d;
};
union block_hdr {
union align a;
/* Actual header... */
struct {
char *endp;
union block_hdr *next;
char *first_avail;
#ifdef POOL_DEBUG
union block_hdr *global_next;
struct pool *owning_pool;
#endif
} h;
};
struct pool {
union block_hdr *first;
union block_hdr *last;
struct cleanup *cleanups;
struct process_chain *subprocesses;
struct pool *sub_pools;
struct pool *sub_next;
struct pool *sub_prev;
struct pool *parent;
char *free_first_avail;
#ifdef ALLOC_USE_MALLOC
void *allocation_list;
#endif
#ifdef POOL_DEBUG
struct pool *joined;
#endif
}; //复杂的链表结构,支持嵌套定义
//从内存池里获取内存
pool * ap_get_shared_mem_pool(size_t size)
{
pool *new_pool;
union block_hdr *blok;
blok = (union block_hdr *) ap_tpf_get_shared_mem(size);
/* if shm fails, it will exit blok will be valid here */
memset((char *) blok, '/0', size);
blok->h.next = NULL;
blok->h.first_avail = (char *) (blok + 1);
blok->h.endp = size + blok->h.first_avail;
new_pool = (pool *) blok->h.first_avail;
blok->h.first_avail += POOL_HDR_BYTES;
new_pool->free_first_avail = blok->h.first_avail;
new_pool->first = new_pool->last = blok;
return new_pool;
}
/*****************************************************************
*
*from http_main.c in apache v1.3.34
*/
static pool *pglobal; /* Global pool */
static pool *pconf; /* Pool for config stuff */
static pool *plog; /* Pool for error-logging files */
static pool *ptrans; /* Pool for per-transaction stuff */
static pool *pchild; /* Pool for httpd child stuff */
static pool *pmutex; /* Pool for accept mutex in child */
static pool *pcommands; /* Pool for -C and -c switches */
二 文档说明
这种工作方式是这样:用于处理特定请求而分配的内存、打开的文件 与一个为该请求分配的资源池绑定。池是一个自身跟踪问题资源的数据结构。
然而,使用它有两个好处: 分配到池中的内存永远不会泄漏(即使你分配了一个临时串又忘了释放它); 以及,对于内存分配,ap_palloc
通常比malloc
快。
池中的内存分配
调用
ap_palloc
把内存分配到池中,它有两个参数, 一个是指向资源池数据结构的指针,另一个是要分配的内存数量(按char
计算)。 在请求处理器内部,得到资源池指针的最普通的方式是察看相关的 request_rec
结构的pool
槽; 因此模块代码中常见下列程序段重复出现:
int my_handler(request_rec *r)
{
struct my_structure *foo;
...
foo = (foo *)ap_palloc (r->pool, sizeof(my_structure));
}
注意没有
ap_pfree
函数 --- ap_palloc
分配的内存只在相关联的资源池清空时被释放。这意味着ap_palloc
不必做像malloc()
那样多的计算; 典型情况下它要做的就是对齐分配大小,生成块指针,再做一个范围检查。
(也存在
ap_palloc
的重负载使用导致一个服务进程变得过份庞大的可能性。有两个解决办法;简单地,你可以用malloc
并确信所有分配的内存都显式地用 free
释放了,或者你可以在主资源池里分配一个子资源池, 在子资源池里分配内存并周期性地清空它。后一个技术在下面关于子资源池的章节里有讨论,,在列目录的代码中有实际使用,主要是为了对数以千计的文件列目录时避免过多的存储分配。)。
注释:ap_palloc ap_pcalloc from allow.c
分配初始化的内存
有几个函数用于分配初始化的内存,使用很频繁。 函数
ap_pcalloc
与ap_palloc
有同样的界面,但是会在返回之前清零所分配内存。 函数ap_pstrdup
以一个资源池和一个char *
为参数,为指针指向的字符串的拷贝分配内存并返回拷贝的指针。 最后ap_pstrcat
是个参数表可变的函数,它的参数有一个资源池指针和至少两个以NULL
结尾的char *
。它要为每个字符串的拷贝的合并分配足够的内存。例如:
ap_pstrcat (r->pool, "foo", "/", "bar", NULL);
返回一个指向包含8个字节、已被初始化为
"foo/bar"
的一块内存的指针。