特点
优点:
将大量小内存的申请聚集到一块,能够比malloc 更快
减少内存碎片,防止内存泄漏
减少内存管理复杂度
缺点:
造成内存空间浪费,以空间换时间
内存池的结构:
struct ngx_pool_s
{
ngx_pool_data_t d; //数据区
size_t max; //内存池最大容量
ngx_chain_t *current; //当前内存池的头
ngx_pool_large_t *large; //大数据块的链表
ngx_pool_cleanup_t *cleanup; //清理函数的链表
ngx_log_t *log; //日志打印
};
//数据区:
typedef struct
{
u_char *last; //数据区已经使用的区域结尾
u_char *end; //当前内存池的结尾 end - last = 剩余容量
ngx_pool_t *next; //指向下一个内存池
ngx_uint_t failed; //失败标记 重新分配内存池
}ngx_pool_data_t;
//大内存区:
struct ngx_pool_large_s
{
ngx_pool_large_t *next; //指向下一个large
void *alloc; //指向数据
};
//用于清理:
struct ngx_pool_cleanup_s
{
ngx_pool_cleanup_pt handler; //清理函数
void *data; //传递给清理函数的数据
ngx_pool_cleanup_t *next; //下一个清理函数headler
};
ngx_creat_pool:创建一个pool
ngx_pool_t * ngx_create_pool(size_t size, ngx_log_t *log)
//传递进的size是实际可用数据区大小 = total-sizeof(ngx_pool_t);
#define NGX_MAX_ALLOC_FROM_POOL (nginx_pagesize - 1)
ngx_pool_t * ngx_create_pool(size_t size, ngx_log_t *log)
{
ngx_pool_t *p = ngx_alloc(size,log);//只分配size大小;可用的要减
if(p == NULL) {return NULL;}
//初始化数据区:
p->d.last = (u_char*)p + size + sizeof(ngx_pool_t);
p->d.end = (u_char*)p + size;
p->d.next = (u_char*)p + NULL;
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;
}
内存分配
ngx_palloc —–内存对齐分配
ngx_pnalloc —内存 不对齐分配
ngx_calloc —–分配内存并清0
void *ngx_palloc(ngx_pool_t,size_t size)
{
u_char *m;
u_char *p;
if(size<=pool->max) //超过max的大块进入large
{
p = pool->current; //得到当前内存池的指针
while(p) //遍历内存池
{
m = ngx_align_ptr(p->d.last,NGX_ALIGNMENT);//对齐last
if((size_t)(p-d.end - m) >= size) //可用大小
{
p->d.last = m + size; //更新last
return m;
}
p = p->d.next;
}
return ngx_palloc_block(pool,size); //内存满了重新分配
}
return ngx_palloc_large(pool,size); //申请大块内存
}
ngx_palloc_block再分配一个内存池
//新内存池大小和父内存池一样大,但是维护部分比父内存池小(ngx_pool_data_t)
static void *ngx_palloc_block(ngx_pool_t *pool,size_t size)
{
u_char *m;
size_t psize;
ngx_pool_t *p,*new,current;
psize = (size_t)(pool->d.end - (u_char*)pool); //计算当前内存池大小
m = ngx_alloc(psize,pool->log);
if(NULL == m){return NULL;}
new = (ngx_pool_t *)m;
//更新指针:
new->d.end = m + psize;
new->d.next = NULL;
new->d.failed = 0;
//重点:
m += sizeof(ngx_pool_data_t);
new->d.next = NULL;
new_.d.last = m + size;
current = pool->current;
//遍历子内存池,找出一个failed大于4的,将新new的内存池链到最后一个内存池后面
for(p = current;p->d.next;p = p->d.next)
{
if(p->d.failed++ > 4)
{
current = p->d.next;
}
}
p->d.next = new;
pool->current = current ? current : new;
return m;
}
ngx_palloc_large分配大内存
static void *ngx_palloc_large(ngx_pool_t *pool,size_t size)
{
void *p;
ngx_uint_t n = 0;
ngx_pool_large_t *large;
p = ngx_alloc(pool,size);
if(p == NULL) return NULL;
//遍历large链表,如果有alloc为空,赋值返回
for(large = pool->large;large;large = large->next)
{
if(large->alloc == NULL)
{
large ->alloc = p;
return p;
}
if(n++>3) break;
//malloc一块ngx_pool_large_t;
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;
}
内存池释放
//大块内存提供free,小块的内存只能等内存池销毁才会释放
ngx_pfree从pool的large中找到,然后释放
void ngx_destroy_pool(ngx_pool_t *pool)
{
ngx_pool_t *p,*n;
ngx_pool_large_t *l;
ngx_pool_cleanup c;
//清理==不太理解
for(c = pool->cleanup;c;c = c->next)
{
if(c->handler)
{
c->handler(c->data);
}
}
//free大块内存
for(l = pool->large;l;l = l->next)
{
if(l->alloc)
{
ngx_free(l->alloc);
}
}
//小块内存
for(p = pool;n = pool->d.next;p = n;n = n->d.next)
{
ngx_free(p);
if(n==NULL) break;
}
}