介绍
假如内存中有存储指向动态开辟内存的指针,调用ngx_pfree
只是简单的释放了大块内存的空间,而其中指针指向的内存空间并没有被释放,这会导致内存泄漏。
为此nginx
内存池提供了一个用户可自己设置的回调(ngx_pool_cleanup_s
)来进行这一类资源的释放,这个清理资源操作对象可能有多个用链表组织,内存图示如下
源代码
注意这个清理操作对象头部信息也是存在小块内存的内存池上
添加清理函数
ngx_pool_cleanup_t *
ngx_pool_cleanup_add(ngx_pool_t *p, size_t size)
{
ngx_pool_cleanup_t *c;
c = ngx_palloc(p, sizeof(ngx_pool_cleanup_t));
if (c == NULL) {
return NULL;
}
if (size) {
c->data = ngx_palloc(p, size);
if (c->data == NULL) {
return NULL;
}
} else {
c->data = NULL;
}
c->handler = NULL;
c->next = p->cleanup; // 头插法
p->cleanup = c;
ngx_log_debug1(NGX_LOG_DEBUG_ALLOC, p->log, 0, "add cleanup: %p", c);
return c;
}
设置清理类对象的伪代码如下
void release(void *p) { free(p); }
ngx_pool_cleanup_t *pclean = ngx_pool_cleanup_add(pool, sizeof(char*));
pclean->handler = &release;
pclean->data = pData->p;
销毁内存池的函数ngx_destroy_pool
void
ngx_destroy_pool(ngx_pool_t *pool)
{
ngx_pool_t *p, *n;
ngx_pool_large_t *l;
ngx_pool_cleanup_t *c;
// 1.释放外部资源,通过调用自己实现的释放资源函数
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);
}
}
// 2.大块内存池释放
for (l = pool->large; l; l = l->next) {
if (l->alloc) {
ngx_free(l->alloc);
}
}
// 3.小块内存池释放
for (p = pool, n = pool->d.next; /* void */; p = n, n = n->d.next) {
ngx_free(p);
if (n == NULL) {
break;
}
}
}