参考:

http://blog.csdn.net/livelylittlefish/article/details/6586946

http://code.google.com/p/nginxsrp/wiki/NginxCodeReview


相关的源码文件为:


- nginx_palloc.h

- nginx_palloc.c

- nginx_alloc.h

- nginx_alloc.c


内存池数据块结构


typedef struct {

u_char *last; // 当前内存池分配到此处,即下一次分配从此处开始

u_char *end; // 内存池结束位置

ngx_pool_t *next; // 内存池里面有很多块内存,这些内存块就是通过该指针连成链表的

ngx_uint_t failed; // 内存池分配失败次数

} ngx_pool_data_t;


内存池结构如下


struct ngx_pool_s {

ngx_pool_data_t d; // 指向内存池的第一个数据块

size_t max; // 内存池数据块的最大值(数目)

ngx_pool_t *current; // 指向当前内存池

ngx_chain_t *chain; // 该指针挂接一个ngx_chain_t结构

ngx_pool_large_t *large; // 大块内存链表,即分配空间超过max的内存

ngx_pool_cleanup_t *cleanup; // 释放内存池的callback

ngx_log_t *log; // 主要用于记录日志信息

};


large内存链表结构


struct ngx_pool_large_s {

ngx_pool_large_t *next; // 指向下一个large内存

void *alloc; // 指向分配的large内存

};


cleanup内存链表结构


struct ngx_pool_cleanup_s {

ngx_pool_cleanup_pt handler; // 指向用于cleanupcleanup内存

void *data; // 指向分配的cleanup内存

ngx_pool_cleanup_t *next; // 指向下一个cleanup内存

};


创建内存池


ngx_pool_t *

ngx_create_pool(size_t size, ngx_log_t *log)

{

ngx_pool_t *p;


p = ngx_memalign(NGX_POOL_ALIGNMENT, size, log);

if (p == NULL) {

return NULL;

}

// 可以看到 last 指向 pool 之后的位置,即下一个pool块分配的位置

p->d.last = (u_char *) p + sizeof(ngx_pool_t);

// end 指向poolsize的最后,即当前pool可容纳的最大尺寸的结束位置

p->d.end = (u_char *) p + size;

p->d.next = NULL;

p->d.failed = 0;


size = size - sizeof(ngx_pool_t);

p->max = (size < NGX_MAX_ALLOC_FROM_POOL) ? size : NGX_MAX_ALLOC_FROM_POOL;


p->current = p;

p->chain = NULL;

p->large = NULL;

p->cleanup = NULL;

p->log = log;


return p;

}


注:其中NGX_MAX_ALLOC_FROM_POOL的定义如下:


/*

* NGX_MAX_ALLOC_FROM_POOL should be (ngx_pagesize - 1), i.e. 4095 on x86.

* On Windows NT it decreases a number of locked pages in a kernel.

*/

#define NGX_MAX_ALLOC_FROM_POOL (ngx_pagesize - 1)


ngx_pagesize的值依赖于OS的,取值如下设置:


ngx_int_t

ngx_os_init(ngx_log_t *log)

{

ngx_uint_t n;


#if (NGX_HAVE_OS_SPECIFIC_INIT)

if (ngx_os_specific_init(log) != NGX_OK) {

return NGX_ERROR;

}

#endif


ngx_init_setproctitle(log);


ngx_pagesize = getpagesize();

ngx_cacheline_size = NGX_CPU_CACHE_LINE;


for (n = ngx_pagesize; n >>= 1; ngx_pagesize_shift++) { /* void */ }

… …

}


其中getpagesize()是由OS提供的。


首先调用ngx_memalign(…)来分配alignedmemory。之后,初始化内存池结构的各个成员,下图为初始化好的内存池的结构图(调用ngx_create_pool(1024,0x80d1c4c)函数)


Nginx内存池实现的了解_第1张图片


销毁内存池


void

ngx_destroy_pool(ngx_pool_t *pool)

{

ngx_pool_t *p, *n;

ngx_pool_large_t *l;

ngx_pool_cleanup_t *c;


for (c = pool->cleanup; c; c = c->next) {

if (c->handler) {

ngx_log_debug1(NGX_LOG_DEBUG_ALLOC, pool->log, 0,

"run cleanup: %p", c);

c->handler(c->data);

}

}


for (l = pool->large; l; l = l->next) {


ngx_log_debug1(NGX_LOG_DEBUG_ALLOC, pool->log, 0, "free: %p", l->alloc);


if (l->alloc) {

ngx_free(l->alloc);

}

}


#if (NGX_DEBUG)

… …

#endif


for (p = pool, n = pool->d.next; /* void */; p = n, n = n->d.next) {

ngx_free(p);


if (n == NULL) {

break;

}

}

}


遍历内存池链表,释放所有内存,包括poollargecleanup链表,如果指定了cleanup回调来释放,则调用cleanuphandler来释放cleanup链表中的内存。


先依次释放poolcleanuplarge类型的链表,最后释放pool本身的链表。


重置内存池


void

ngx_reset_pool(ngx_pool_t *pool)

{

ngx_pool_t *p;

ngx_pool_large_t *l;


// 先遍历large链表,释放large内存

for (l = pool->large; l; l = l->next) {

if (l->alloc) {

ngx_free(l->alloc);

}

}


pool->large = NULL;


for (p = pool; p; p = p->d.next) {

p->d.last = (u_char *) p + sizeof(ngx_pool_t);

}

}


使用ngx_palloc()分配内存


void *

ngx_palloc(ngx_pool_t *pool, size_t size)

{

u_char *m;

ngx_pool_t *p;


if (size <= pool->max) { // 如果需要分配的size大于max,则使用palloc_large来分配

p = pool->current; // 小于max,则从current开始遍历pool链表

do {

// 每次从last处开始分配aligned内存

m = ngx_align_ptr(p->d.last, NGX_ALIGNMENT);


if ((size_t) (p->d.end - m) >= size) {

// 如果分配的内存够用,则就从此处分配,并调整last

p->d.last = m + size;

return m;

}


p = p->d.next;

} while (p);

// 表示链表里没有能够分配size大小的内存节点

// 则生成一个新的节点,并在其中分配内存

return ngx_palloc_block(pool, size);

}

// 大于max的,就在large中进行分配

return ngx_palloc_large(pool, size);

}


下图为在调用ngx_palloc(pool,200)分配200B的内存池物理结构图:


Nginx内存池实现的了解_第2张图片


内存池的物理结构


Nginx内存池实现的了解_第3张图片


注:文章中的图都摘自

(http://blog.csdn.net/livelylittlefish/article/details/6586946)