设为首页 收藏本站
查看: 757|回复: 0

[经验分享] nginx 源码学习笔记(七)——内存分配相关源码分析

[复制链接]

尚未签到

发表于 2016-12-28 08:00:32 | 显示全部楼层 |阅读模式
内存分配相关
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) 初始化为0return p;}
  c. ngx_memalign 返回基于一个指定的alignment大小的数值为对齐基数的空间
  d.ngx_free 内存释放操作
2.   nginx内存池
  为了方便系统模块对内存的使用,方便内存的管理,nginx自己是信了进程池机制来进行内存的分配和释放,首先nginx会在特定的生命周期帮你统一建立内存池,当需要进行内存分配的时候同一通过内存池中的内存进行分配,最后nginx会在适当的时候释放内存吃的资源,开发者只要在需要的时候对内存进行申请即可,不用过多考虑释放的问题,这也就是在os/unix/ngx_alloc.c文件中没有看到free操作的原因吧。
下面来看一下内存池的主要结构:
ngx_palloc.hstruct 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.htypedef struct ngx_pool_s        ngx_pool_t;typedef struct ngx_chain_s       ngx_chain_t;
DSC0000.gif
  下面是几个比较重要的操作

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;                                 //没有nextp->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;}//销毁内存池voidngx_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;}}#endiffor (p = pool, n = pool->d.next; /* void */; p = n, n = n->d.next) {//遍历链表 ,释放内存空间ngx_free(p);if (n == NULL) {break;}}}//重置内存池voidngx_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_tngx_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;               // 增加cleanupngx_log_debug1(NGX_LOG_DEBUG_ALLOC, p->log, 0, "add cleanup: %p", c);return c;                    //返回结构体分配的空间}

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.iyunv.com/thread-320349-1-1.html 上篇帖子: nginx 源码学习笔记(九)——基本容器——queue 下篇帖子: nginx配置—图片不存在时给一张默认图片
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表