nginx内存池学习

特点

优点:
将大量小内存的申请聚集到一块,能够比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;
    }

}

猜你喜欢

转载自blog.csdn.net/m18706819671/article/details/80461955