概述 Nginx在大多数涉及到内存使用的地方都用到了ngx_pool_t这个结构体以及和这个结构体相关的一些函数。这个结构体是Nginx用来管理内存的用的,涉及到内存的申请、释放以及一些相关资源的管理。当我们需要去和内存打交道的时候,不需要去花费时间在担心某块内存没有释放造成野指针的情况。
Nginx在内存管理中将内存分为两种类型,一种是小块内存,一种是大块内存。这两种内存以ngx_pool_s结构体中max作为区分界限。其中小块内存是在内存池的数据块(对应结构体中的d)中进行分配,在大部分情况下的小块内存的分配过程中,只需要去移动一个内部的指针便可。在分配大块内存的过程中,每次都会去申请一块内存。因此对比来看,小块内存的申请效率更加方便。具体内容可以参考源码中src/core/ngx_palloc.h|.c的相关内容。
数据结构定义 需释放资源 需释放资源结构体ngx_pool_cleanup_t主要管理一些需要释放的资源,比如关闭文件,删除文件等。作为ngx_pool_t中cleanup链表的节点类型。
1 2 3 4 5 6 7 8 9 typedef  void  (*ngx_pool_cleanup_pt) (void  *data) typedef  struct  ngx_pool_cleanup_s   ngx_pool_cleanup_t ;struct  ngx_pool_cleanup_s  {    ngx_pool_cleanup_pt   handler;       void                  *data;          ngx_pool_cleanup_t    *next;      }; 
大块内存 大块内存ngx_pool_large_t是Nginx的内存池中的一种内存类型,当在需要分配超过一定大小的内存时会发挥作用。
1 2 3 4 5 6 7 typedef  struct  ngx_pool_large_s   ngx_pool_large_t ;struct  ngx_pool_large_s  {    ngx_pool_large_t      *next;          void                  *alloc;     }; 
数据块 数据块ngx_pool_data_t是内存池中实际分配内存的地方,这个地方主要是分配小内存,有一点需要注意的是大块内存节点的空间(ngx_pool_large_t)也是在这里申请的。
1 2 3 4 5 6 typedef  struct  {    u_char               *last;          u_char               *end;           ngx_pool_t            *next;          ngx_uint_t             failed;    } ngx_pool_data_t ; 
内存池 内存池ngx_pool_t是Nginx中用来管理内存的入口
1 2 3 4 5 6 7 8 9 10 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;         ngx_pool_cleanup_t    *cleanup;       ngx_log_t             *log ;       }; 
相关操作 ngx_create_pool 创建一个size大小的内存池
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 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; } 
ngx_destroy_pool 销毁内存池
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 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)          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; ; 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; ; p = n, n = n->d.next) {         ngx_free(p);         if  (n == NULL ) {             break ;         }     } } 
ngx_reset_pool 重置内存池
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 void ngx_reset_pool(ngx_pool_t  *pool) {     ngx_pool_t         *p;     ngx_pool_large_t   *l;          for  (l = pool->large; l; l = l->next) {         if  (l->alloc) {             ngx_free(l->alloc);         }     }          for  (p = pool; p; p = p->d.next) {         p->d.last = (u_char *) p + sizeof (ngx_pool_t );         p->d.failed = 0 ;     }     pool->current = pool;     pool->chain = NULL ;     pool->large = NULL ; } 
ngx_palloc 申请size大小的内存并对其
1 2 3 4 5 6 7 8 9 10 11 12 13 14 void  *ngx_palloc(ngx_pool_t  *pool, size_t  size) {          #if  !(NGX_DEBUG_PALLOC)     if  (size <= pool->max) {         return  ngx_palloc_small(pool, size, 1 );     } #endif           return  ngx_palloc_large(pool, size); } 
ngx_pnalloc 申请size大小内存不对其
1 2 3 4 5 6 7 8 9 10 11 12 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); } 
ngx_palloc_small 申请小块内存
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 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); } 
ngx_palloc_block 申请一个新的内存池,其实是一个数据块。因为Nginx是以链表的形式去管理内存的,无论是在小块内存还是大块内存的分配上。数据块结构体ngx_pool_data_t的next是一个ngx_pool_t类型的指针,当现有内存池的数据块剩余空间不够的时候,我们需要去创建一个新的ngx_pool_t结构体来挂在当前数据块的next下,而这个新的ngx_pool_t结构体d后面的所有字段值都是和之前内存池里面的值相同的。为了节约内存,因此在这个方法里面,我们会看到申请挂载的ngx_pool_t结构体的可分配起始位置是在申请内存返回地址的基础上加上的ngx_pool_data_t的大小,和创建的时候加上ngx_pool_t的大小不一样。具体可以参照下面的示意图。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 static  void  *ngx_palloc_block(ngx_pool_t  *pool, size_t  size) {     u_char      *m;     size_t        psize;     ngx_pool_t   *p, *new ;          psize = (size_t ) (pool->d.end - (u_char *) pool);          m = ngx_memalign(NGX_POOL_ALIGNMENT, psize, pool->log );     if  (m == NULL ) {         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 );     m = ngx_align_ptr(m, NGX_ALIGNMENT);          new ->d.last = m + size;          for  (p = pool->current; p->d.next; p = p->d.next) {         if  (p->d.failed++ > 4 ) {             pool->current = p->d.next;         }     }          p->d.next = new ;     return  m; } 
ngx_palloc_large 申请大块内存
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 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; } 
ngx_pmemalign 申请大块内存并对其
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 void  *ngx_pmemalign(ngx_pool_t  *pool, size_t  size, size_t  alignment) {     void               *p;     ngx_pool_large_t   *large;     p = ngx_memalign(alignment, size, pool->log );     if  (p == NULL ) {         return  NULL ;     }     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; } 
ngx_pfree 释放内存池中的某一个大块内存
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 ngx_int_t ngx_pfree(ngx_pool_t  *pool, void  *p) {     ngx_pool_large_t   *l;     for  (l = pool->large; l; l = l->next) {         if  (p == l->alloc) {             ngx_log_debug1(NGX_LOG_DEBUG_ALLOC, pool->log , 0 ,                            "free: %p" , l->alloc);             ngx_free(l->alloc);             l->alloc = NULL ;             return  NGX_OK;         }     }     return  NGX_DECLINED; } 
ngx_pcalloc 在内存池中申请内存并清零
1 2 3 4 5 6 7 8 9 10 11 12 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; } 
资源相关操作 剩下的就是一些和资源相关的函数了,这类就不再一一详细的解读了。
1 2 3 4 ngx_pool_cleanup_t  *ngx_pool_cleanup_add (ngx_pool_t  *p, size_t  size) void  ngx_pool_run_cleanup_file (ngx_pool_t  *p, ngx_fd_t  fd) void  ngx_pool_cleanup_file (void  *data) void  ngx_pool_delete_file (void  *data)