nginx-1.0.4源码分析—内存池结构ngx_pool_t及内存管理_第1页
nginx-1.0.4源码分析—内存池结构ngx_pool_t及内存管理_第2页
nginx-1.0.4源码分析—内存池结构ngx_pool_t及内存管理_第3页
nginx-1.0.4源码分析—内存池结构ngx_pool_t及内存管理_第4页
nginx-1.0.4源码分析—内存池结构ngx_pool_t及内存管理_第5页
已阅读5页,还剩21页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、Content0.序1 .内存池结构1.1 ngx_pool_t 结构1.2 其他相关结构1.3 ngx_pool_t 的逻辑结构2 .内存池操作2.1 创建内存池2.2 销毁内存池2.3 重置内存池2.4 分配内存2.4.1 ngx_palloc()函数分析2.4.2 ngx_palloc_block()函数分析2.5 释放内存2.6 注册 cleanup2.7 内存池的物理结构3 .一个例子3.1 代码3.2 如何编译3.3 运行结果4.小结 5.致谢0.序nginx 对内存的管理由其自己实现的内存池结构 ngx_pool_t 来完成,本文重点叙述 nginx 的内存管理。nginx 内存

2、管理相关文件:2./src/os/unix/ngx_alloc.h/.c内存相关的操作,封装了最基本的内存分配函数如 free/malloc/memalign/posix_memalign,分另1J 被封装为ngx_free,ngx_alloc/ngx_calloc,ngx_memalign6.%2ngx_alloc:封装 malloc 分配内存7.%2ngx_calloc:封装malloc 分配内存,并初始化空间内容为 08.%2ngx_memalign:返回基于一个指定 alignment 的大小为 size 的内存空间,且其地址为 alignment 的整数倍,alignment 为 2

3、 的哥。3./src/core/ngx_palloc.h/.c封装创建/销毁内存池,从内存池分配空间等函数.表示 nginx-1.0.4 代码目录,本文为/usr/src/nginx-1.0.4。2.%2.内存池结构nginx 对内存的管理均统一完成,例如,在特定的生命周期统一建立内存池(如 main 函数系统启动初期即分配 1024B 大小的内存池),需要内存时统一分配内存池中的内存,在适当的时候释放内存池的内存(如关闭 http 链接时调用 ngx_destroy_pool 进行销毁)。因此,开发者只需在需要内存时进行申请即可,不用过多考虑内存的释放等问题,大大提高了开发的效率。先看一下内

4、存池结构。ngx_pool_t 结构此处统下概念,内存池的数据块:即分配内存在这些数据块中进行,一个内存池可以有多一个内存池数据块。nginx 的内存池结构如下。00048:typedefstruct00049:u_char*last;当前内存池分配到此处,即下一次分配从此处开始00050:u_char*end;内存池结束位置00051:ngx_pool_t*next;内存池里面有很多块内存,这些内存块就是通过该指针连成链表的00052:ngx_uint_tfailed;内存池分配失败次数00053:ngx_pool_data_t;内存池的数据块位置信息00054:00055:00057:ng

5、x_pool_data_td;内存池的数据块00058:size_tmax;内存池数据块的最大值00059:ngx_pool_t*current;指向当前内存池00060:ngx_chain_t*chain;/该指针挂接一个 ngx_chain_t 结构00061:ngx_pool_large_t*large;大块内存链表,即分配空间超过 max 的内存00062:ngx_pool_cleanup_t*cleanup;/释放内存池的 callback00063:ngx_log_t*log;日志信息00064:;其中,sizeof(ngx_pool_data_t)=16B,sizeof(ngx_

6、pool_t)=40B。nginx 将几乎所有的结构体放在 ngx_core.h 文件中重新进行了申明,如下。typedefstructngx_module_sngx_module_t;typedefstructngx_conf_sngx_conf_t;typedefstructngx_cycle_sngx_cycle_t;typedefstructngx_pool_sngx_pool_t;typedefstructngx_chain_sngx_chain_t;typedefstructngx_log_sngx_log_t;typedefstructngx_array_sngx_array_t

7、;typedefstructngx_open_file_sngx_open_file_t;typedefstructngx_command_sngx_command_t;typedefstructngx_event_stypedefstructngx_event_aio_sngx_event_aio_t;typedefstructngx_connection_sngx_connection_t;其他相关结构其他与内存池相干的数据结构,如清除资源的 cleanup 链表,分配的大块内存链表等,如下。00015:/*00016:*NGX_MAX_ALLOC_FROM_POOLshouldbe(ng

8、x_pagesize-1),i.e.4095onx86.00017:*OnWindowsNTitdecreasesanumberoflockedpagesinakernel.00018:*/00019:#defineNGX_MAX_ALLOC_FROM_POOL(ngx_pagesize-1)/在 x86 体系结构下,该值一般为 4096B,即 4K00020:00021:#defineNGX_DEFAULT_POOL_SIZE(16*1024)00022:00023:#defineNGX_POOL_ALIGNMENT1600024:#defineNGX_MIN_POOL_SIZE00025:

9、ngx_align(sizeof(ngx_pool_t)+2*sizeof(ngx_pool_large_t),00026:NGX_POOL_ALIGNMENT)00027:00028:ngx_event_t;00029:typedefvoid(*ngx_pool_cleanup_pt)(void*data);00030:00031:typedefstructngx_pool_cleanup_sngx_pool_cleanup_t;00032:00033:structngx_pool_cleanup_s00034:ngx_pool_cleanup_pthandler;00035:void*da

10、ta;指向要清除的数据00036:ngx_pool_cleanup_t*next;下一个 cleanupcallback00037:;00038:00039:00040:typedefstructngx_pool_large_sngx_pool_large_t;00041:00042:structngx_pool_large_s00043:ngx_pool_large_t*next;指向下一块大块内存00044:void*alloc;指向分配的大块内存00045:;.00067:typedefstruct/cleanup 的 callback 类型00069:u_char*name;00070

11、:ngx_log_t*log;00071:ngx_pool_cleanup_file_t;00072:(gdb)pgetpagesize()$18=4096全局变量 ngx_pagesize 的初始化是在如下函数中完成的。ngx_int_tngx_os_init(ngx_log_t*log)ngx_uint_tn;#if(NGX_HAVE_OS_SPECIFIC_INIT)if(ngx_os_specific_init(log)!=NGX_OK)returnNGX_ERROR;#endifngx_init_setproctitle(log);/*该函数为 glibc 的库函数,由系统调用实现,

12、返回内核中的 PAGE_SIZE,该值依赖体系结构*/ngx_pagesize=getpagesize();./src/os/unix/ngx_posix_gx_cacheline_size=NGX_CPU_CACHE_LINE;.这些数据结构之间的关系,请参考后面的图。ngx_pool_t 的逻辑结构这些数据结构逻辑结构图如下。注:本文采用 UML 的方式画出该图。3.%2.内存池操作创建内存池创建内存池有 ngx_create_pool()函数完成,代码如下。00015:ngx_pool_t*00016:ngx_create_pool(size_tsize,ngx_log_t*log)00

13、017:00018:ngx_pool_t*p;00019:00020:p=ngx_memalign(NGX_POOL_ALIGNMENT,size,log);00021:if(p=NULL)00022:returnNULL;00023:00024:00025:p-d.last=(u_char*)p+sizeof(ngx_pool_t);/last 指向 ngx_pool_t 结构体之后数据取起始位置00026:p-d.end=(u_char*)p+size;/end 指向分配的整个 size 大小的内存的末尾00027:p-d.next=NULL;00028:p-d.failed=0;0002

14、9:00030:size=size-sizeof(ngx_pool_t);00031:p-max=(sizecurrent=p;00034:p-chain=NULL;00035:p-large=NULL;00036:p-cleanup=NULL;00037:p-log=log;00038:00039:returnp;00040:例如,调用 ngx_create_pool(1024,0 x80d1c4c)后,创建的内存池物理结构如下图。销毁内存池销毁内存池由如下函数完成。voidngx_destroy_pool(ngx_pool_t*pool)该函数将遍历内存池链表,所有释放内存,如果注册了 c

15、lenup(也是一个链表结构),亦将遍历该 cleanup 链表结构依次调用 clenup 的 handler 清理。同时,还将遍历 large 链表,释放大块内存。重置内存池重置内存池由下面的函数完成。voidngx_reset_pool(ngx_pool_t*pool);该函数将释放所有 large 内存,并且将 d-last 指针重新指向 ngx_pool_t 结构之后数据区的开始位置,同刚创建后的位置相同。分配内存内存分配的函数如下。void*ngx_palloc(ngx_pool_t*pool,size_tsize);void*ngx_pnalloc(ngx_pool_t*pool,

16、size_tsize);void*ngx_pcalloc(ngx_pool_t*pool,size_tsize);void*ngx_pmemalign(ngx_pool_t*pool,size_tsize,size_talignment);返回值为分配的内存起始地址。选择其中的两个函数进行分析,其他的也很好理解,省略。ngx_palloc()函数分析ngx_palloc()代码如下,分析请参考笔者所加的注释。00115:void*00116:ngx_palloc(ngx_pool_t*pool,size_tsize)00117:00118:u_char*m;00119:ngx_pool_t*p

17、;00120:00121:if(sizemax)/判断待分配内存与 max 值00122:00123:p=pool-current;小于 max 值,则从 current 节点开始遍历 pool 链表00124:00126:m=ngx_align_ptr(p-d.last,NGX_ALIGNMENT);00127:00128:if(size_t)(p-d.end-m)=size)00129:p-d.last=m+size;在该节点指向的内存块中分配 size 大小的内存00130:00131:returnm;00132:00133:00134:p=p-d.next;00135:00136:wh

18、ile(p);00137:00138:returnngx_palloc_block(pool,size);/链表里没有能分配 size 大小内存的节点,则生成一个新的节点并在其中分配内存00139:00140:00141:returnngx_palloc_large(pool,size);大于 max 值,贝 U 在 large 链表里分配内存00142:例如,在 2.1 节中创建的内存池中分配 200B 的内存,调用 ngx_palloc(pool,200)后,该内存池物理结构如下图。00125:do(lx略OxWJcJL口萍,HILI-734Bngx_palloc_block()函数分析

19、ngx_palloc_block 函数代码如下,分析请参考笔者所加的注释。00175:staticvoid*00176:ngx_palloc_block(ngx_pool_t*pool,size_tsize)00177:00178:u_char*m;00179:size_tpsize;00180:ngx_pool_t*p,*new,*current;00181:00182:psize=(size_t)(pool-d.end-(u_char*)pool);00183:00184:m=ngx_memalign(NGX_POOL_ALIGNMENT,psize,pool-log);分配一块与pool

20、 大小相同的内存00185:if(m=NULL)00186:returnNULL;00187:00188:00189:new=(ngx_pool_t*)m;00190:00191:new-d.end=m+psize;/设置 end 指针00192:new-d.next=NULL;00193:new-d.failed=0;00194:00195:m+=sizeof(ngx_pool_data_t);/让 m 指向该块内存 ngx_pool_data_t 结构体之后数据区起始位置00196:m=ngx_align_ptr(m,NGX_ALIGNMENT);/按 4 字节对齐00197:new-d.

21、last=m+size;/在数据区分配 size 大小的内存并设置 last 指针00198:00199:current=pool-current;00200:计算 pool 的大小00201:for(p=current;p-d.next;p=p-d.next)00202:if(p-d.failed+4)/failed 的值只在此处被修改00203:current=p-d.next;失败 4 次以上移动 current 指针00204:00205:00206:00207:p-d.next=new;/将这次分配的内存块 new 加入该内存池00208:00209:pool-current=cur

22、rent?current:new;00210:00211:returnm;00212:注意:该函数分配一块内存后,last 指针指向的是 ngx_pool_data_t 结构体(大小 16B)之后数据区的起始位置。而创建内存池时时,last 指针指向的是 ngx_pool_t 结构体(大小 40B)之后数据区的起始位置。结合 2.7 节的内存池的物理结构,更容易理解。释放内存请参考如下函数,不再赘述。ngx_int_tngx_pfree(ngx_pool_t*pool,void*p)需要注意的是该函数只释放 large 链表中注册的内存,普通内存在 ngx_destroy_pool 中统一释放

23、。注册 cleanup请参考如下函数,该函数实现也很简单,此处不再赘述。ngx_pool_cleanup_t*ngx_pool_cleanup_add(ngx_pool_t*p,size_tsize)内存池的物理结构针对本文第 3 节的例子,画出的内存池的物理结构如下图。从该图也能看出 2.4 节的结论,即内存池第一块内存前 40 字节为 ngx_pool_t 结构,后续加入的内存块前 16 个字节为ngx_pool_data_t 结构,这两个结构之后便是真正可以分配内存区域。因此,本文 Reference 中的内存分配相关中的图是有一点点小问题的,并不是每一个节点的前面都是 ngx_pool

24、_t 结构。W-r一一EW一一F,iE-HLW*I-WWRir-*-E:l-ErW:,rFEF-,f*W1E,!E!T.W*1nsx_pooL_t实现为一不住表转而-将将中中:lbUxUnextT1(J山旧山旧uB+tlii-TIitTTTTTn+uB+tlii-TIitTTTTTn+I1II1I-B+utrn+utTn+f1TTTt+f1TTTTtT1rtTS4+a-B+utrn+utTn+f1TTTt+f1TTTTtT1rtTS4+aT TxT:+*-xT:+*-电-工T Tim*im*nJnJ-T*1H-T*1Hm,;+:m,;+: , ,+I.+I.I.mt+1nI.mt+1nN NG

25、1KG1KK K的内存管理+“FLKtnr;;FEJUxNr4HrHD0心心;GxHriHH.7;一一W”电电。血。血4然而然而3.一个例子理解并掌握开源软件的最好方式莫过于自己写一些测试代码,或者改写软件本身,并进行调试来进一步理解开源软件的原理和设计方法。本节给出一个创建内存池并从中分配内存的简单例子。3.1 代码 ngx_pool_t_test.c如何编译这个问题是编写测试代码或者改写软件本身最迫切需要解决的问题,否则,编写的代码无从编译或运行,那也无从进行调试并理解软件了。如何对自己编写的测试代码进行编译,可参考 Linux 平台代码覆盖率测试-编译过程自动化及对链接的解释、Linux

26、 平台如何编译使用 Googletest 写的单元测试?。我们要做的是学习这种编译工程的方法, 针对该例子, 笔者编写的 makefile文件如下。一一这便是本节的主要目的。CXX=gccCXXFLAGS+=-g-Wall-WextraNGX_ROOT=/usr/src/nginx-1.0.4TARGETS=ngx_pool_t_testTARGETS_C_FILE=$(TARGETS).cCLEANUP=rm-f$(TARGETS)*.oall:$(TARGETS)clean:$(CLEANUP)CORE_INCS=-I.-I$(NGX_ROOT)/src/core-I$(NGX_ROOT)/src/event-I$(NGX_ROOT)/src/event/modules-I$(NGX_ROOT)/src/os/unix-I$(NGX_ROOT)/objsNGX_PALLOC=$(NGX_ROOT)/objs/src/core/ngx_palloc.oNGX_STRING=$(NGX_ROOT)/objs/src/core/ngx_string.oNGX_ALLOC=$(NGX_ROOT)/objs/src/os/unix/ngx_alloc.o$(TARGETS)

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论