nginx 源码学习笔记(七)

来源:互联网 发布:淘宝助理5 for mac 编辑:程序博客网 时间:2024/06/05 11:10

内存分配相关

1.      系统功能封装

内存相关的操作主要在os/unix/ngx_alloc.{h,c} 和 core/ngx_palloc.{h,c}中。

其中os/unix/ngx_alloc.{h,c}封装了最基本的内存分配函数,是对c原有的malloc/free/memalign等函数的封装,对应函数为:

a.ngx_alloc:对malloc进行了简单的封装;

    void *      ngx_alloc(size_t size, ngx_log_t *log)      {          void  *p;          p = malloc(size);          if (p == NULL) {              ngx_log_error(NGX_LOG_EMERG, log, ngx_errno,                            "malloc(%uz) failed", size);    }          ngx_log_debug2(NGX_LOG_DEBUG_ALLOC, log, 0, "malloc: %p:%uz", p, size);          return p;      }  

b.ngx_calloc:使用ngx_alloc分配内存,并且把内存赋值0:

    void *      ngx_calloc(size_t size, ngx_log_t *log)      {          void  *p;          p = ngx_alloc(size, log);          if (p) {     ngx_memzero(p, size);    }//在core/ngx_string.h中定义      // #define ngx_memzero(buf, n)       (void) memset(buf, 0, n) 初始化为0          return p;      }  

c. ngx_memalign  返回基于一个指定的alignment大小的数值为对齐基数的空间

d.ngx_free    内存释放操作


2.      nginx内存池

为了方便系统模块对内存的使用,方便内存的管理,nginx自己施行了进程池机制来进行内存的分配和释放,首先nginx会在特定的生命周期帮你统一建立内存池,当需要进行内存分配的时候同一通过内存池中的内存进行分配,最后nginx会在适当的时候释放内存吃的资源,开发者只要在需要的时候对内存进行申请即可,不用过多考虑释放的问题,这也就是在os/unix/ngx_alloc.c文件中没有看到free操作的原因吧。

 

下面来看一下内存池的主要结构:

    <span style="font-size:16px;">ngx_palloc.h      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;      };      typedef struct {          u_char               *last;          u_char               *end;          ngx_pool_t           *next;          ngx_uint_t            failed;      } ngx_pool_data_t;            ngx_core.h      typedef struct ngx_pool_s        ngx_pool_t;      typedef struct ngx_chain_s       ngx_chain_t;      </span>  




    <span style="font-size:16px;">src/core/ngx_palloc.c      //创建内存池      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);    //初始指向ngx_pool_t结构体后面          p->d.end = (u_char *) p + size;                   //整个结构体的结尾          p->d.next = NULL;                                 //没有next          p->d.failed = 0;                size = size - sizeof(ngx_pool_t);    //剩余大小      p->max = (size < NGX_MAX_ALLOC_FROM_POOL) ? size : NGX_MAX_ALLOC_FROM_POOL;//最大不超过NGX_MAX_ALLOC_FROM_POOL      //#define NGX_MAX_ALLOC_FROM_POOL  (ngx_pagesize - 1)                p->current = p;          p->chain = NULL;          p->large = NULL;          p->cleanup = NULL;          p->log = log;                return p;      }            //销毁内存池      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) {//如果注册了clenup(一种链表结构),会依次调用clenup的handler进行清理              if (c->handler) {                  ngx_log_debug1(NGX_LOG_DEBUG_ALLOC, pool->log, 0,                                 "run cleanup: %p", c);                  c->handler(c->data);              }          }                for (l = pool->large; l; l = l->next) { //遍历链表,释放所有large内存                    ngx_log_debug1(NGX_LOG_DEBUG_ALLOC, pool->log, 0, "free: %p", l->alloc);                    if (l->alloc) {                  ngx_free(l->alloc);              }          }            #if (NGX_DEBUG)  //等译debug级别,如果为true,会打印日志                /*          * we could allocate the pool->log from this pool          * so we cannot use this log while free()ing the 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;              }          }            #endif                for (p = pool, n = pool->d.next; /* void */; p = n, n = n->d.next) {//遍历链表 ,释放内存空间              ngx_free(p);                    if (n == NULL) {                  break;              }          }      }            //重置内存池      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) { //释放掉所有large段内存              if (l->alloc) {                  ngx_free(l->alloc);              }          }                pool->large = NULL;                for (p = pool; p; p = p->d.next) {              p->d.last = (u_char *) p + sizeof(ngx_pool_t);将指针重新指向ngx_pool_t(和创建时一样)          }      }            //从内存池里分配内存      void * ngx_palloc(ngx_pool_t *pool, size_t size)      void * ngx_pnalloc(ngx_pool_t *pool, size_t size)      void * ngx_pmemalign(ngx_pool_t *pool, size_t size, size_t alignment)      void * ngx_pcalloc(ngx_pool_t *pool, size_t size)            这里以ngx_palloc为例讲解,其他大同小异:      void *      ngx_palloc(ngx_pool_t *pool, size_t size)      {          u_char      *m;          ngx_pool_t  *p;          if (size <= pool->max) { //判断分配内存是否大于pool->max,如果小于等于              p = pool->current; //尝试从链表的current开始遍历,              do {                  m = ngx_align_ptr(p->d.last, NGX_ALIGNMENT);      //#define ngx_align_ptr(p,a)        //(u_char *) (((uintptr_t) (p) + ((uintptr_t) a - 1)) & ~((uintptr_t) a - 1))                        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);//如果无法分配内存,就生成一个新的节点,同时pool->current指针指向新的位置          }          return ngx_palloc_large(pool, size);  //如果分配的内存大于pool->max则在large链表分配一段内存      }            //释放指定的内存      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) {        //存在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;      }//由代码可以看出,这个操作只有在内存large链表里面注册内存才会真正释放,如果分配的是普通的内存,则会在destory_pool的时候统一释放。            //注册cleanup回调函数      ngx_pool_cleanup_t *      ngx_pool_cleanup_add(ngx_pool_t *p, size_t size)      {          ngx_pool_cleanup_t  *c;          c = ngx_palloc(p, sizeof(ngx_pool_cleanup_t));  //分配cleanup空间          if (c == NULL) {              return NULL;          }          if (size) {              c->data = ngx_palloc(p, size);         //为cleanup结构体分配data空间              if (c->data == NULL) {                  return NULL;              }          } else {              c->data = NULL;          }          c->handler = NULL;          c->next = p->cleanup;          p->cleanup = c;               // 增加cleanup          ngx_log_debug1(NGX_LOG_DEBUG_ALLOC, p->log, 0, "add cleanup: %p", c);          return c;                    //返回结构体分配的空间      }</span>  


原创粉丝点击