nginx内存池详解Word文档格式.docx

上传人:b****6 文档编号:8389984 上传时间:2023-05-11 格式:DOCX 页数:22 大小:136.42KB
下载 相关 举报
nginx内存池详解Word文档格式.docx_第1页
第1页 / 共22页
nginx内存池详解Word文档格式.docx_第2页
第2页 / 共22页
nginx内存池详解Word文档格式.docx_第3页
第3页 / 共22页
nginx内存池详解Word文档格式.docx_第4页
第4页 / 共22页
nginx内存池详解Word文档格式.docx_第5页
第5页 / 共22页
nginx内存池详解Word文档格式.docx_第6页
第6页 / 共22页
nginx内存池详解Word文档格式.docx_第7页
第7页 / 共22页
nginx内存池详解Word文档格式.docx_第8页
第8页 / 共22页
nginx内存池详解Word文档格式.docx_第9页
第9页 / 共22页
nginx内存池详解Word文档格式.docx_第10页
第10页 / 共22页
nginx内存池详解Word文档格式.docx_第11页
第11页 / 共22页
nginx内存池详解Word文档格式.docx_第12页
第12页 / 共22页
nginx内存池详解Word文档格式.docx_第13页
第13页 / 共22页
nginx内存池详解Word文档格式.docx_第14页
第14页 / 共22页
nginx内存池详解Word文档格式.docx_第15页
第15页 / 共22页
nginx内存池详解Word文档格式.docx_第16页
第16页 / 共22页
nginx内存池详解Word文档格式.docx_第17页
第17页 / 共22页
nginx内存池详解Word文档格式.docx_第18页
第18页 / 共22页
nginx内存池详解Word文档格式.docx_第19页
第19页 / 共22页
nginx内存池详解Word文档格式.docx_第20页
第20页 / 共22页
亲,该文档总共22页,到这儿已超出免费预览范围,如果喜欢就下载吧!
下载资源
资源描述

nginx内存池详解Word文档格式.docx

《nginx内存池详解Word文档格式.docx》由会员分享,可在线阅读,更多相关《nginx内存池详解Word文档格式.docx(22页珍藏版)》请在冰点文库上搜索。

nginx内存池详解Word文档格式.docx

∙如free/malloc/memalign/posix_memalign,分别被封装为ngx_free,ngx_alloc/ngx_calloc,ngx_memalign

∙ngx_alloc:

封装malloc分配内存

∙ngx_calloc:

封装malloc分配内存,并初始化空间内容为0

∙ngx_memalign:

返回基于一个指定alignment的大小为size的内存空间,且其地址为alignment的整数倍,alignment为2的幂。

(2)./src/core/ngx_palloc.h/.c

∙封装创建/销毁内存池,从内存池分配空间等函数

.表示nginx-1.0.4代码目录,本文为/usr/src/nginx-1.0.4。

nginx对内存的管理均统一完成,例如,在特定的生命周期统一建立内存池(如main函数系统启动初期即分配1024B大小的内存池),需要内存时统一分配内存池中的内存,在适当的时候释放内存池的内存(如关闭http链接时调用ngx_destroy_pool进行销毁)。

因此,开发者只需在需要内存时进行申请即可,不用过多考虑内存的释放等问题,大大提高了开发的效率。

先看一下内存池结构。

此处统一一下概念,内存池的数据块:

即分配内存在这些数据块中进行,一个内存池可以有多一个内存池数据块。

nginx的内存池结构如下。

00048:

typedefstruct{

00049:

u_char*last;

//当前内存池分配到此处,即下一次分配从此处开始

00050:

u_char*end;

//内存池结束位置

00051:

ngx_pool_t*next;

//内存池里面有很多块内存,这些内存块就是通过该指针连成链表的

00052:

ngx_uint_tfailed;

//内存池分配失败次数

00053:

}ngx_pool_data_t;

//内存池的数据块位置信息

00054:

00055:

00056:

structngx_pool_s{//内存池头部结构

00057:

ngx_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;

//释放内存池的callback

00063:

ngx_log_t*log;

//日志信息

00064:

};

其中,sizeof(ngx_pool_data_t)=16B,sizeof(ngx_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;

typedefstructngx_open_file_sngx_open_file_t;

typedefstructngx_command_sngx_command_t;

typedefstructngx_file_sngx_file_t;

typedefstructngx_event_sngx_event_t;

typedefstructngx_event_aio_sngx_event_aio_t;

typedefstructngx_connection_sngx_connection_t;

其他与内存池相干的数据结构,如清除资源的cleanup链表,分配的大块内存链表等,如下。

00015:

/*

00016:

*NGX_MAX_ALLOC_FROM_POOLshouldbe(ngx_pagesize-1),i.e.4095onx86.

00017:

*OnWindowsNTitdecreasesanumberoflockedpagesinakernel.

00018:

*/

00019:

#defineNGX_MAX_ALLOC_FROM_POOL(ngx_pagesize-1)//在x86体系结构下,该值一般为4096B,即4K

00020:

00021:

#defineNGX_DEFAULT_POOL_SIZE(16*1024)

00022:

00023:

#defineNGX_POOL_ALIGNMENT16

00024:

#defineNGX_MIN_POOL_SIZE\

00025:

ngx_align((sizeof(ngx_pool_t)+2*sizeof(ngx_pool_large_t)),\

00026:

NGX_POOL_ALIGNMENT)

00027:

00028:

00029:

typedefvoid(*ngx_pool_cleanup_pt)(void*data);

//cleanup的callback类型

00030:

00031:

typedefstructngx_pool_cleanup_sngx_pool_cleanup_t;

00032:

00033:

structngx_pool_cleanup_s{

00034:

ngx_pool_cleanup_pthandler;

00035:

void*data;

//指向要清除的数据

00036:

ngx_pool_cleanup_t*next;

//下一个cleanupcallback

00037:

00038:

00039:

00040:

typedefstructngx_pool_large_sngx_pool_large_t;

00041:

00042:

structngx_pool_large_s{

00043:

ngx_pool_large_t*next;

//指向下一块大块内存

00044:

void*alloc;

//指向分配的大块内存

00045:

...

00067:

00068:

ngx_fd_tfd;

00069:

u_char*name;

00070:

00071:

}ngx_pool_cleanup_file_t;

00072:

(gdb)pgetpagesize()

$18=4096

全局变量ngx_pagesize的初始化是在如下函数中完成的。

./src/os/unix/ngx_posix_init.c

ngx_int_t

ngx_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;

}

#endif

ngx_init_setproctitle(log);

/**该函数为glibc的库函数,由系统调用实现,返回内核中的PAGE_SIZE,该值依赖体系结构*/

ngx_pagesize=getpagesize();

ngx_cacheline_size=NGX_CPU_CACHE_LINE;

...

}

这些数据结构之间的关系,请参考后面的图。

这些数据结构逻辑结构图如下。

注:

本文采用UML的方式画出该图。

创建内存池有ngx_create_pool()函数完成,代码如下。

ngx_pool_t*

ngx_create_pool(size_tsize,ngx_log_t*log)

{

ngx_pool_t*p;

p=ngx_memalign(NGX_POOL_ALIGNMENT,size,log);

if(p==NULL){

returnNULL;

p->

d.last=(u_char*)p+sizeof(ngx_pool_t);

//last指向ngx_pool_t结构体之后数据取起始位置

d.end=(u_char*)p+size;

//end指向分配的整个size大小的内存的末尾

d.next=NULL;

d.failed=0;

size=size-sizeof(ngx_pool_t);

max=(size<

NGX_MAX_ALLOC_FROM_POOL)?

size:

NGX_MAX_ALLOC_FROM_POOL;

//最大不超过4095B

current=p;

chain=NULL;

large=NULL;

cleanup=NULL;

log=log;

returnp;

例如,调用ngx_create_pool(1024,0x80d1c4c)后,创建的内存池物理结构如下图。

销毁内存池由如下函数完成。

voidngx_destroy_pool(ngx_pool_t*pool)

该函数将遍历内存池链表,所有释放内存,如果注册了clenup(也是一个链表结构),亦将遍历该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,size_tsize);

void*ngx_pcalloc(ngx_pool_t*pool,size_tsize);

void*ngx_pmemalign(ngx_pool_t*pool,size_tsize,size_talignment);

返回值为分配的内存起始地址。

选择其中的两个函数进行分析,其他的也很好理解,省略。

ngx_palloc()代码如下,分析请参考笔者所加的注释。

00115:

void*

00116:

ngx_palloc(ngx_pool_t*pool,size_tsize)

00117:

00118:

u_char*m;

00119:

00120:

00121:

if(size<

=pool->

max){//判断待分配内存与max值

00122:

00123:

p=pool->

current;

//小于max值,则从current节点开始遍历pool链表

00124:

00125:

do{

00126:

m=ngx_align_ptr(p->

d.last,NGX_ALIGNMENT);

//指针对齐

00127:

00128:

if((size_t)(p->

d.end-m)>

=size){

00129:

d.last=m+size;

//在该节点指向的内存块中分配size大小的内存

00130:

00131:

returnm;

00132:

00133:

00134:

p=p->

d.next;

//遍历到下一个数据块

00135:

00136:

}while(p);

00137:

00138:

returnngx_palloc_block(pool,size);

//链表里没有能分配size大小内存的节点,则生成一个新的节点并在其中分配内存

00139:

00140:

00141:

returnngx_palloc_large(pool,size);

//大于max值,则在large链表里分配内存

00142:

关于ngx_align_ptr宏:

#definengx_align_ptr(p,a)\

(u_char*)(((uintptr_t)(p)+((uintptr_t)a-1))&

~((uintptr_t)a-1))

例如,在2.1节中创建的内存池中分配200B的内存,调用ngx_palloc(pool,200)后,该内存池物理结构如下图。

ngx_palloc_block函数代码如下,分析请参考笔者所加的注释。

00175:

staticvoid*

00176:

ngx_palloc_block(ngx_pool_t*pool,size_tsize)

00177:

00178:

00179:

size_tpsize;

00180:

ngx_pool_t*p,*new,*current;

00181:

00182:

psize=(size_t)(pool->

d.end-(u_char*)pool);

//计算pool的大小

00183:

00184:

m=ngx_memalign(NGX_POOL_ALIGNMENT,psize,pool->

log);

//分配一块与pool大小相同的内存

00185:

if(m==NULL){

00186:

00187:

00188:

00189:

new=(ngx_pool_t*)m;

00190:

00191:

new->

d.end=m+psize;

//设置end指针

00192:

00193:

00194:

00195:

m+=sizeof(ngx_pool_data_t);

//让m指向该块内存ngx_pool_data_t结构体之后数据区起始位置

00196:

m=ngx_align_ptr(m,NGX_ALIGNMENT);

//按4字节对齐

00197:

//在数据区分配size大小的内存并设置last指针

00198:

00199:

current=pool->

00200:

00201:

for(p=current;

d.next){

00202:

if(p->

d.failed++>

4){//failed的值只在此处被修改

00203:

current=p->

//失败4次以上移动current指针(失败次数大于5时,不再使用该内存块)

00204:

00205:

00206:

00207:

d.next=new;

//将这次分配的内存块new加入该内存池

00208:

00209:

pool->

current=current?

current:

new;

00210:

00211:

00212:

注意:

该函数分配一块内存后,last指针指向的是ngx_pool_data_t结构体(大小16B)之后数据区的起始位置。

而创建内存池时时,last指针指向的是ngx_pool_t结构体(大小40B)之后数据区的起始位置。

结合2.7节的内存池的物理结构,更容易理解。

请参考如下函数,不再赘述。

ngx_int_t 

ngx_pfree(ngx_pool_t*pool,void*p)

需要注意的是该函数只释放large链表中注册的内存,普通内存在ngx_destroy_pool中统一释放。

请参考如下函数,该函数实现也很简单,此处不再赘述。

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_t结构。

理解并掌握开源软件的最好方式莫过于自己写一些测试代码,或者改写软件本身,并进行调试来进一步理解开源软件的原理和设计方法。

本节给出一个创建内存池并从中分配内存的简单例子。

/**

*ngx_pool_ttest,totestngx_palloc,ngx_palloc_block,ngx_palloc_large

#include<

stdio.h>

#include"

ngx_config.h"

ngx_conf_file.h"

nginx.h"

ngx_core.h"

ngx_string.h"

ngx_palloc.h"

volatilengx_cycle_t*ngx_cycle;

voidngx_log_error_core(ngx_uint_tlevel,ngx_log_t*log,ngx_err_terr,

constchar*fmt,...)

voiddump_pool(ngx_pool_t*pool)

while(pool)

printf("

pool=0x%x\n"

pool);

.d\n"

);

.last=0x%x\n"

pool->

d.last);

.end=0x%x\n"

d.end);

.next=0x%x\n"

d.next);

.failed=%d\n"

d.failed);

.max=%d\n"

max);

.current=0x%x\n"

current);

.chain=0x%x\n"

chain);

.large=0x%x\n"

large);

.cleanup=0x%x\n"

cleanup);

.log=0x%x\n"

availablepoolmemory=%d\n\n"

d.end-pool->

pool=pool->

intmain()

ngx_pool_t*pool;

--------------------------------\n"

createanewpool:

\n"

pool=ngx_create_pool(1024,NULL);

dump_pool(pool);

allocblock1fromthepool:

ngx_palloc(pool,512);

allocblock2fromthepool:

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

当前位置:首页 > 人文社科 > 设计艺术

copyright@ 2008-2023 冰点文库 网站版权所有

经营许可证编号:鄂ICP备19020893号-2