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>
- nginx 源码学习笔记(七)
- nginx 源码学习笔记(七)——内存分配相关源码分析
- nginx 源码学习笔记(七)——内存分配相关源码分析
- nginx 源码学习笔记(一)
- nginx 源码学习笔记(三)
- nginx 源码学习笔记(四)
- nginx 源码学习笔记(二)
- nginx 源码学习笔记(五)
- nginx 源码学习笔记(六)
- Nginx学习笔记(七):HTTP配置模型
- Nginx学习笔记七Nginx的Web缓存服务
- Nginx学习笔记七Nginx的Web缓存服务
- Nginx学习笔记七Nginx的Web缓存服务
- 【nginx源码学习与运用 七】基数树结构ngx_radix_tree_t
- [源码学习] -- yii2源码学习笔记(七) -- model类
- 深度学习(七)caffe源码c++学习笔记
- 深度学习(七)caffe源码c++学习笔记
- 深度学习(七)caffe源码c++学习笔记
- oracle如何对sys用户进行审计(oracle on windows)
- HDOJ 2955 Robberies
- 电脑桌面图标背景出现蓝色解决方法
- Android 应用初始化及窗体事件(按键)的分发
- 关于在view当中增加toolbar的问题
- nginx 源码学习笔记(七)
- 常用C#字符串函数大全
- 不更改数据库默认隔离级别,如何避免丢失更新(lost update)
- 猜扑克的小游戏 复习多线程
- 分享10个超赞的画布Canvas,SVG和CSS3相关的jQuery插件
- SQL LEFT JOIN
- 【Cocos2d-X】场景切换方式总汇
- C# vs C++之一:委托 vs 函数指针
- 对象不对支持属性或方法