网站制作学习网经验与学习→正文:nginx内存池管理分析
字体:

nginx内存池管理分析

经验与学习 2012/10/18 18:22:26  点击:不统计

原载于:文章来源:www.forasp.cn网站制作学习

最近修改nginx看了一下nginx的内存管理代码,将nginx的内存池管理拿出来分享一下
/////////////////////////////////////////
//1.创建一个pool内存池,并返回起始地址
//////////////////////////////////////////
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); 
    //ngx_memalign()函数执行内存分配,该函数的实现在src/os/unix/ngx_alloc.c文件中(假定NGX_HAVE_POSIX_MEMALIGN被定义): 
     
    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);//将size减去管理结构的大小,然后判断
    p->max = (size < NGX_MAX_ALLOC_FROM_POOL) ? size : NGX_MAX_ALLOC_FROM_POOL;  
    //最大不超过4095B,别忘了上面NGX_MAX_ALLOC_FROM_POOL的定义 
     
    p->current = p;//将管理结构的current指向自己起始地址,下面的定义chain,large,cleanupd等
    p->chain = NULL;
    p->large = NULL; 
    p->cleanup = NULL; 
    p->log = log; 
     
    return p; 
}
////////////////////////////////////////////////////////////////////////
//2.申请对齐的内存空间,并返回申请成功空间的起始地址(上面函数9行调用了)
///////////////////////////////////////////////////////////////////////
void *  
ngx_memalign(size_t alignment, size_t size, ngx_log_t *log) 

    void  *p; 
    int    err; 
     
    err = posix_memalign(&p, alignment, size); 
    //该函数分配以alignment为对齐的size字节的内存大小,其中p指向分配的内存块。 
     
    if (err) { 
        ngx_log_error(NGX_LOG_EMERG, log, err, 
            "posix_memalign(%uz, %uz) failed", alignment, size); 
        p = NULL; 
    } 
     
    ngx_log_debug3(NGX_LOG_DEBUG_ALLOC, log, 0, 
        "posix_memalign: %p:%uz @%uz", p, size, alignment); 
     
    return p; 
}
////////////////////////////////////////////////////////////////////////
//3.销毁内存池 pool ,也就是上面1创建的内存池
//////////////////////////////////////////////////////////////////////////
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) {//循环调用内存池中所有内容的clearup回调函数
        if (c->handler) { 
            ngx_log_debug1(NGX_LOG_DEBUG_ALLOC, pool->log, 0, 
                "run cleanup: %p", c); 
            c->handler(c->data); 
        } 
    } 
    //前面讲到,cleanup指向析构函数,用于执行相关的内存池销毁之前的清理工作,如文件的关闭等, 
    //清理函数是一个handler的函数指针挂载。因此,在这部分,对内存池中的析构函数遍历调用。 
     
    for (l = pool->large; l; l = l->next) {  //清理对应的pool下面挂在的large大的内存空间,擦已用原始的free
        ngx_log_debug1(NGX_LOG_DEBUG_ALLOC, pool->log, 0, "free: %p", l->alloc);           
        if (l->alloc) { 
            ngx_free(l->alloc); 
        } 
    } 
    //这一部分用于清理大块内存,ngx_free实际上就是标准的free函数, 
    //即大内存块就是通过malloc和free操作进行管理的。 
     
#if (NGX_DEBUG) 
     
    /**
    * we could allocate the pool->log from this pool
    * so we can not use this log while the free()ing the pool
    */ 
    //如果再debug模式下打印所有的pool使用信息,当循环到最后一个pool之后,则跳出循环
    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; 
        } 
    } 
    //只有debug模式才会执行这个片段的代码,主要是log记录,用以跟踪函数销毁时日志记录。 
#endif 
    //这里是彻底销毁所有的pool,当前pool的->d的链表,直到结束。
    for (p = pool, n = pool->d.next; /** void */; p = n, n = n->d.next) { 
        ngx_free(p); 
         
        if (n == NULL) { 
            break; 
        } 
    } 

//该片段彻底销毁内存池本身。
//////////////////////////////////////////////////////////////////
//4.重置内存池pool
/////////////////////////////////////////////////////////////////
void  
ngx_reset_pool(ngx_pool_t *pool) 

    ngx_pool_t        *p; 
    ngx_pool_large_t  *l; 
    //查询当前pool下面挂的所有的large内存块直接free
    for (l = pool->large; l; l = l->next) { 
        if (l->alloc) { 
            ngx_free(l->alloc); 
        } 
    } 
    //将pool的large的指针置空
    pool->large = NULL; 
    //将所有的pool->d的的pool的last指向 当前所属pool的起始位置(pool开头+pool结构大小的偏移)
    for (p = pool; p; p = p->d.next) { 
        p->d.last = (u_char *) p + sizeof(ngx_pool_t); 
    } 
}
///////////////////////////////////////////////////////////////////
//5.内存分配函数,从pool中申请size大小的空间
///////////////////////////////////////////////////////////////////

void *  
ngx_palloc(ngx_pool_t *pool, size_t size) 

    u_char      *m; 
    ngx_pool_t  *p; 
     
    //判断待分配内存与max值 
    //1、小于max值,则从current结点开始遍历pool链表 
    if (size <= pool->max) {//判断当前的pool大小是不是足够申请的,如果足够的话。
        //pool取当前指向的pool
  p = pool->current;
         
        do { 
            //执行对齐操作, 
            //即以last开始,计算以NGX_ALIGNMENT对齐的偏移位置指针,,获取对齐偏移后的位置,从last对齐,也许就是last也许要+n个b(具体看内存管理)
            m = ngx_align_ptr(p->d.last, NGX_ALIGNMENT); 
          
            //然后计算end值减去这个偏移指针位置的大小是否满足索要分配的size大小, 
            //如果满足,则移动last指针位置,并返回所分配到的内存地址的起始地址,这样就从pool分配了size大小的空间
            if ((size_t) (p->d.end - m) >= size) { 
                p->d.last = m + size;   
                //在该结点指向的内存块中分配size大小的内存                   
                return m; 
            } 
             
            //如果不满足,则查找当前pool链上的下一个pool
            p = p->d.next; 
             
        } while (p);//如果又下一个pool则继续,如果没有则跳出,表示找不到何时的size 
         
        //如果没有合适的pool则,重新申请pool     
        return ngx_palloc_block(pool, size);    //2.4.1节分析 
         
    } 
    //2、如果大于max值,则执行大块内存分配的函数ngx_palloc_large,在large链表里分配内存 
    return ngx_palloc_large(pool, size);        //2.4.2节分析 

/////////////////////////////////////////////////////////////////
//6. 当需要的内存大于pool目前可用内存大小时,则创建一个新的pool
/////////////////////////////////////////////////////////////////

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); 
    //计算当前的pool的大小,即当前pool的整块的大小,也就是整个pool的大小(包括pool的结构和数据空间)
     
    m = ngx_memalign(NGX_POOL_ALIGNMENT, psize, pool->log);//创建对齐的一个pool大小空间
    if (m == NULL) { 
        return NULL; 
    } 
    //执行按NGX_POOL_ALIGNMENT对齐方式的内存分配,假设能够分配成功,则继续执行后续代码片段。 
    //将m强转换为pool结构
 new = (ngx_pool_t *) m;
    //设置pool的结束为止 
    new->d.end = m + psize; 
 //将新pool的next置空
    new->d.next = NULL; 
    new->d.failed = 0; 
    //执行该block相关的初始化。 
    //偏移pool的写入内容地址 
    m += sizeof(ngx_pool_data_t); 
    //让m指向该块内存ngx_pool_data_t结构体之后数据区起始位置 
    m = ngx_align_ptr(m, NGX_ALIGNMENT);//将m进行内存对齐
    new->d.last = m + size;//将使用到的位置偏移,也就是用了size大小的空间,则将last偏移
    //获取当盘的current pool
    current = pool->current; 
    //循环当前pool,循环如果错误超过4次的pool则将current指向下一个 
    for (p = current; p->d.next; p = p->d.next) { 
        if (p->d.failed++ > 4) { 
            current = p->d.next; 
            //失败4次以上移动current指针,如果所有的pool错误都错误3次了,则最后current指向了null
        } 
    } 
    //将新的pool挂到 当盘pool->d链的最后一个
    p->d.next = new; 
    //将分配的block链入内存池 
    //如果所有的pool错误次数都大于3,则将current指向新的pool     
    pool->current = current ? current : new; 
 
     
    return m; 

////////////////////////////////////////////
//7. 创建大的内存空间
//注释:要的内存大于pool最大可分配内存大小时,此时首先判断size已经大于pool->max的大小了,所以直接调用ngx_palloc_large进行大内存分配
///////////////////////////
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);//直接分配size空间
    if (p == NULL) { 
        return NULL; 
    } 
     
    n = 0; 
     
  //如果在前三个large中有空闲结构(没有指向具体的地址),则直接将申请的空间给当前的large结构
    for (large = pool->large; large; large = large->next) { 
        if (large->alloc == NULL) { 
            large->alloc = p; 
            return p; 
        } 
        //如果链表大于3 则将重新申请一个管理结构,并挂到链头部(下面继续)
        if (n++ > 3) { 
            break; 
        } 
    } 
     
    //如果该pool之前并未分配large内存,则就没有ngx_pool_large_t来管理大块内存 
    //执行ngx_pool_large_t结构体的分配,用于来管理large内存块。 
    large = ngx_palloc(pool, sizeof(ngx_pool_large_t));//这里是从当前的pool里面分出一个large的结构空间
    if (large == NULL) { 
        ngx_free(p); 
        return NULL; 
    } 
    //将large结构赋值,并将large挂到当前盘pool的large的最开始
    large->alloc = p; 
    large->next = pool->large; 
    pool->large = large; 
     
    return p; 
}
//////////////////////////////////////////////////////////////////
//8.直接分配large的大空间 在7 的236行调用
/////////////////////////////////////////////////////////////////
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; 
}
//////////////////////////////////////////////////////////////////
//9.直接分配large的大空间并置零 ,调用上面的函数8
/////////////////////////////////////////////////////////////////
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; 
}


<%77w%77%2Ef%6F%72p%73%70%2Ec%6E>

·上一篇:Window8学习开发 >>    ·下一篇:c绑定cpu处理内容 >>
推荐文章
最新文章