为了避免出现内存碎片,避免反复向操作系统申请内存,Nginx设计了简单的内存池。nginx内存池根据用户请求逐级分配,逐级释放。整体上内存池分为三个等级进程级(master/worker),connection级(用户连接),request级(请求处理)三个不同的层级。启动启动时创建main级别内存池,然后master/work进程创建内存池,当有连接进来的时候,创建一个connection内存池,request请求进来时在connection内存池上创建一个request内存池。request处理完成后,逐级释放内存池。最终释放master进程内存池。实现的基本数据结构包含ngx_pool_data_t和ngx_pool_t两个数据结构。
1.数据结构
内存池数据块结构
typedef struct {
u_char *last;/*内存池已分配内存块的结束位置,管理内存池的使用情况*/
u_char *end;/*内存池在内存中的结束位置,管理内存池的分配状况*/
ngx_pool_t *next;/*内存块下个节点位置,nginx内存是通过链表管理的*/
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_pool_large_t *large;/*分配超过max空间的内存链表*/
ngx_pool_cleanup_t *cleanup;/*内存池释放callback*/
ngx_log_t *log;/*内存池操作日志信息*/
};
2。内存池操作
2.1创建内存池
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;
}
p->d.last = (u_char *) p + sizeof(ngx_pool_t);
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;
}
2.2销毁内存池
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);
}
}
#if (NGX_DEBUG)
/*
* we could allocate the pool->log from this pool
* so we cannot use this log while free()ing the pool
*/
for (l = pool->large; l; l = l->next) {
ngx_log_debug1(NGX_LOG_DEBUG_ALLOC, pool->log, 0, "free: %p", l->alloc);
}
for (p = pool, n = pool->d.next; /* void */; p = n, n = n->d.next) {
ngx_log_debug2(NGX_LOG_DEBUG_ALLOC, pool->log, 0,
"free: %p, unused: %uz", p, p->d.end - p->d.last);
if (n == NULL) {
break;
}
}
#endif
for (l = pool->large; l; l = l->next) {
if (l->alloc) {
ngx_free(l->alloc);
}
}
for (p = pool, n = pool->d.next; /* void */; p = n, n = n->d.next) {
ngx_free(p);
if (n == NULL) {
break;
}
}
}
通过内存池的代码可以看出,Nginx内存使用是在自己的进程内使用的,nginx只是将同一个进程内碎片内存的聚集到一起统一分配,统一释放。减少了大内存块的整体申请和释放避免了频繁申请小内存,降低内存碎片的产生等问题。