Nginx内存池(大块内存的申请和释放)
从ngx_palloc函数可用看到,Nginx内存池大小内存的分界在内存池头部ngx_pool_t 的max成员下记录,最大不超过4095个字节,对于大于max的内存申请,都属于大块内存,通过ngx_palloc_large函数来申请。
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);
}
ngx_palloc_large函数的定义如下:
static void *
ngx_palloc_large(ngx_pool_t *pool, size_t size)
{
void *p;
ngx_uint_t n;
ngx_pool_large_t *large;
p = ngx_alloc(size, pool->log);
if (p == NULL) {
return NULL;
}
n = 0;
for (large = pool->large; large; large = large->next) {
if (large->alloc == NULL) {
large->alloc = p;
return p;
}
if (n++ > 3) {
break;
}
}
large = ngx_palloc_small(pool, sizeof(ngx_pool_large_t), 1);
if (large == NULL) {
ngx_free(p);
return NULL;
}
large->alloc = p;
large->next = pool->large;
pool->large = large;
return p;
}
大块内存通过ngx_alloc来申请,ngx_alloc对malloc做了一层包装,申请失败则返回空指针,并会记录日志。之后的操作我们需要先了解大块内存是如何释放的。
在nginx内存池中,是不提供小块内存池的回收的,但是用来记录大块内存的ngx_pool_large_t,是通过ngx_palloc_small记录在小块内存当中的,在释放大块内存的时候,会把ngx_pool_large_t管理的alloc对应的内存释放掉,但并没有把ngx_pool_large_t释放。
大块内存的释放函数定义如下:
ngx_int_t
ngx_pfree(ngx_pool_t *pool, void *p)
{
ngx_pool_large_t *l;
for (l = pool->large; l; l = l->next) {
if (p == l->alloc) {
ngx_log_debug1(NGX_LOG_DEBUG_ALLOC, pool->log, 0,
"free: %p", l->alloc);
ngx_free(l->alloc);
l->alloc = NULL;
return NGX_OK;
}
}
return NGX_DECLINED;
}
释放大块内存时,会遍历内存池的large,如果找到则释放alloc并置空,
返回来看大块内存的申请操作,大块内存申请成功时要把大块内存记录在ngx_pool_large_t的large下,nginx内存池会检查前三个节点已经空闲的ngx_pool_large_t,如果没有则直接在小块内存池中申请一个ngx_pool_large_t来记录这块新申请的大块内存,用头插法把新的ngx_pool_large_t节点记录在ngx_pool_large_t的large下。