Nginx申请内存函数有如下几个:
void *
ngx_palloc(ngx_pool_t *pool, size_t size)
{
#if !(NGX_DEBUG_PALLOC)
if (size <= pool->max) {
return ngx_palloc_small(pool, size, 1);
}
#endif
return ngx_palloc_large(pool, size);
}
void *
ngx_pnalloc(ngx_pool_t *pool, size_t size)
{
#if !(NGX_DEBUG_PALLOC)
if (size <= pool->max) {
return ngx_palloc_small(pool, size, 0);
}
#endif
return ngx_palloc_large(pool, size);
}
void *
ngx_pcalloc(ngx_pool_t *pool, size_t size)
{
void *p;
p = ngx_palloc(pool, size);
if (p) {
ngx_memzero(p, size);
}
return p;
}
其中ngx_palloc函数是考虑内存对齐的,而ngx_pnalloc是不考虑内存对齐的,ngx_pcalloc调用的还是ngx_palloc,只是对一个初始化为0的一个操作,主要分析的是ngx_palloc函数。
参数size是申请内存块的大小,如果size大于小块内存分配的上限,申请的就是大块内存,否则申请的就是小块内存。
先看小块内存的申请过程,ngx_palloc_small函数的定义:
static ngx_inline void *
ngx_palloc_small(ngx_pool_t *pool, size_t size, ngx_uint_t align)
{
u_char *m;
ngx_pool_t *p;
p = pool->current;
do {
m = p->d.last;
if (align) {
m = ngx_align_ptr(m, NGX_ALIGNMENT);
}
if ((size_t) (p->d.end - m) >= size) {
p->d.last = m + size;
return m;
}
p = p->d.next;
} while (p);
return ngx_palloc_block(pool, size);
}


首先用p指向分配小块内存的当前块,如果考虑字节对齐的话,会把p->d.last提升到NGX_ALIGNMENT的整数倍,NGX_ALIGNMENT是一个跟平台相关的宏,32位系统下是4,64位下是8,需要注意的是不是把申请的内存提升,而是把可用内存的起始地址提升,没有全部利用内存池的全部空间。
如果提升后的可用大小大于申请的空间,把p->d.last = m + size;,m 返回即可。
如果当前内存池块的可用大小不足,就回去下个内存块去找。如果已有的内存块都不满足,就会通过ngx_palloc_block函数再申请一个内存池块,提供使用。ngx_palloc_block函数除了申请新的内存块,还有一些维护内存池高性能的一些额外操作,函数定义如下:
static void *
ngx_palloc_block(ngx_pool_t *pool, size_t size)
{
u_char *m;
size_t psize;
ngx_pool_t *p, *new;
psize = (size_t) (pool->d.end - (u_char *) pool);
m = ngx_memalign(NGX_POOL_ALIGNMENT, psize, pool->log);
if (m == NULL) {
return NULL;
}
new = (ngx_pool_t *) m;
new->d.end = m + psize;
new->d.next = NULL;
new->d.failed = 0;
m += sizeof(ngx_pool_data_t);
m = ngx_align_ptr(m, NGX_ALIGNMENT);
new->d.last = m + size;
for (p = pool->current; p->d.next; p = p->d.next) {
if (p->d.failed++ > 4) {
pool->current = p->d.next;
}
}
p->d.next = new;
return m;
}
ngx_palloc_block申请的新内存池块的头部信息不在是用ngx_pool_t 维护,而是用ngx_pool_data_t来维护,ngx_pool_data_t的结构比ngx_pool_t小,它的成员足以维护额外内存池块,可以省出更多的空间使用,申请的大小和头部块的大小一致。
把需要维护的成员更新后,会对前面的块记录申请失败且需要开新块的次数+1,如果需要开新块的次数超过4次,说明这个块剩余的内存已经很小了,那么这块内存块就不再参与分配,把pool->current改为下个内存池块。
最后再把新申请的内存池块串到next指针下。

最后最后需要注意:Nginx内存池分配的小块内存,是不提供回收释放的!