1.基本数据结构
1)最顶层
\src\core\ngx_palloc.h中 ngx_pool_s -- 内存池基本数据结构,整个内存池是由该结构构成的链表
struct ngx_pool_s {
ngx_pool_data_t d;
size_t max; //单个内存池节点容量的最大值
ngx_pool_t *current; //指向当前的内存池节点
ngx_chain_t *chain; //该指针挂接一个ngx_chain_t结构;
ngx_pool_large_t *large; //指向大块内存链表头
ngx_pool_cleanup_t *cleanup; //释放内存池时的清理动作
ngx_log_t *log; //关联的日志对象
};
typedef struct ngx_pool_s ngx_pool_t;
\src\core\ngx_palloc.h中 ngx_pool_data_t -- 内存池数据块
typedef struct {
u_char *last; //内存池节点已分配的末位地址,下一次分配会尝试从此开始
u_char *end; //内存池节点的结束位置
ngx_pool_t *next; //next指向下一个内存池节点
ngx_uint_t failed;//当前内存池节点分配失败次数
} ngx_pool_data_t;
大块内存结构:
typedef struct ngx_pool_large_s ngx_pool_large_t;
struct ngx_pool_large_s {
ngx_pool_large_t *next;
void *alloc;
};
Note:
**头节点中的 “头节点信息” 有具体的作用,后续节点中的“头节点信息”被用作分配区。 所以,大块内存链表都是挂载在头节点中的large指针的。
2)内存申请、释放函数
void *ngx_palloc(ngx_pool_t *pool, size_t size);//使用了内存对齐,速度快,但可能会有少量的内存浪费
void *ngx_pnalloc(ngx_pool_t *pool, size_t size);//没有使用内存对齐
void *ngx_pcalloc(ngx_pool_t *pool, size_t size);//内部调用了口 gx_palloc并且把内存块清零。
ngx_int_t ngx_pfree(ngx_pool_t *pool, void *p);
创建内存池的函数 ngx_pool_t * ngx_create_pool(size_t size, ngx_log_t *log)
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);//申请size 字节的堆内存空间
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; //当前只有一个节点所以为null
p->large = NULL;
p->cleanup = NULL;
p->log = log;
return p;
}
从内存池中取出size大小的空间 void * ngx_pnalloc(ngx_pool_t *pool, size_t 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);
}
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);
}
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;
}
销毁内存池 void ngx_destroy_pool(ngx_pool_t *pool):
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;
}
}
}
Ref: