上述代码中,调用ngx_alloc执行内存分配:
void *ngx_alloc(size_t size, ngx_log_t *log)
{
void *p;
p = malloc(size);
//从这里可以看到,ngx_alloc实际上就是调用malloc函数分配内存的。
if (p == NULL) {
ngx_log_error(NGX_LOG_EMERG, log, ngx_errno,
"malloc() %uz bytes failed", size);
}
ngx_log_debug2(NGX_LOG_DEBUG_ALLOC, log, 0, "malloc: %p:%uz", p, size);
return p;
}
2.4.2、ngx_pcalloc与ngx_pmemalign函数
ngx_pcalloc是直接调用palloc分配好内存,然后进行一次0初始化操作。ngx_pcalloc的源码如下:
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_pmemalign将在分配size大小的内存并按alignment对齐,然后挂到large字段下,当做大块内存处理。ngx_pmemalign的源码如下:
void *ngx_pmemalign(ngx_pool_t *pool, size_t size, size_t alignment)
{
void *p;
ngx_pool_large_t *large;
p = ngx_memalign(alignment, size, pool->log);
if (p == NULL) {
return NULL;
}
large = ngx_palloc(pool, sizeof(ngx_pool_large_t));
if (large == NULL) {
ngx_free(p);
return NULL;
}
large->alloc = p;
large->next = pool->large;
pool->large = large;
return p;
}
其余的不再详述。nginx提供给我们使用的内存分配接口,即上述本2.4节中这4种函数,至此,都已分析完毕。
2.5、释放内存
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链表中注册的内存,普通内存在ngx_destroy_pool中统一释放。
2.6、注册cleanup
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;
}
2.7、文件相关
一些文件相关的操作函数如下,此处就不在详述了。
voidngx_pool_run_cleanup_file(ngx_pool_t *p, ngx_fd_t fd)
{
//....
}
void
ngx_pool_cleanup_file(void *data)
{
//....
}
void
ngx_pool_delete_file(void *data)
{
//...
}
2.8、内存池的物理结构
针对本文前几节的例子,画出的内存池的物理结构如下图。
从该图也能看出2.4节的结论,即内存池第一块内存前40字节为ngx_pool_t结构,后续加入的内存块前16个字节为ngx_pool_data_t结构,这两个结构之后便是真正可以分配内存区域。
全文总结来自淘宝数据共享平台blog内的一篇文章对上述Nginx源码剖析之内存池,与内存管理总结得很好,特此引用之,作为对上文全文的一个总结:
Nginx的内存池实现得很精巧,代码也很简洁。总的来说,所有的内存池基本都一个宗旨:申请大块内存,避免"细水长流"。
3.1、创建一个内存池