4内存池文档格式.docx
- 文档编号:19442667
- 上传时间:2023-01-06
- 格式:DOCX
- 页数:10
- 大小:75.64KB
4内存池文档格式.docx
《4内存池文档格式.docx》由会员分享,可在线阅读,更多相关《4内存池文档格式.docx(10页珍藏版)》请在冰豆网上搜索。
一个内存池就是这样一连串的内存块组成。
当需要用到内存的时候,调用此内存池定义好的接口GetMemory(),而需要删除的时候FreeMemory()。
而GetMemory和FreeMemory干了什么呢?
GetMemory只是简单返回内存池中可用空间的地址。
而FreeMemory干了两件事情:
一:
改变UsedSize的值,二:
重新初始化这一内存区域。
3.nginx中的内存池
3.1nginx内存池的结构表示
首先我们看一下nginx内存池的定义:
代码
structngx_pool_s{
ngx_pool_data_td;
//表示数据区域
size_tmax;
//内存池能容纳数据的大小
ngx_pool_t*current;
//当前内存池块(nginx中的内存池是又一连串的内存池链表组成的,应该指向最后一个fail>
4的内存池的后继)
ngx_chain_t*chain;
//主要为了将内存池连接起来
ngx_pool_large_t*large;
//大块的数据
ngx_pool_cleanup_t*cleanup;
//清理函数
ngx_log_t*log;
//写log
};
nginx中的内存池和普通的有比较大的不同。
nginx中的内存池是由N个内存池链表
组成的,当一个内存池满了以后,就会从下一个内存池中提取空间来使用。
对于ngx_pool_data_t的定义非常简单:
typedefstruct{
u_char*last;
u_char*end;
ngx_pool_t*next;
ngx_uint_tfailed;
}ngx_pool_data_t;
其中last表示当前数据区域的已经使用的数据的结尾。
end表示当前内存池的结尾。
next表示下一个内存池,前面已经说过,再nignx中,当一个内存池空间
不足的时候,它不会扩大其空间,而是再新建一个内存池,组成一个内存池链表。
failed标志申请内存的时候失败的次数。
在理解了这个结构体后面的就非常简单了。
current表示当前可分配内存的内存池。
chain表示内存池链表。
large表示大块的数据。
对于ngx_pool_large_t定义如下:
structngx_pool_large_s{
ngx_pool_large_t*next;
void*alloc;
此结构体的定义也是非常简单的。
一个内存地址的指针已经指向下一个地址的指针。
这里再解释下为什么需要有large数据块。
当一个申请的内存空间大小比内存池的大小还要大的时候,
malloc一块大的空间,再内存池用保留这个地址的指针。
Cleanup保持存着内存池被销毁的时候的清理函数。
typedefvoid(*ngx_pool_cleanup_pt)(void*data);
structngx_pool_cleanup_s{
ngx_pool_cleanup_pthandler;
void*data;
ngx_pool_cleanup_t*next;
ngx_pool_cleanup_pt是一个函数指针的典型用法,
在这个结果中保存这需要清理的数据指针以及相应的清理函数,让内存池销毁
或其他需要清理内存池的时候,可以调用此结构体中的handler。
下面是我画的一张nginx的内存池的结构图。
3.2nginx内存池源代码分析
要大体了解一个内存池,只需要了解其池子的创建,内存的分配以及池子的销毁即可。
下面就分析下
ngx_pool_t的这个3个方面。
注:
其中有些代码可能与ngx_pool中的源代码有所差异,但是整体意思绝对是一样的,本人的修改,只是为了更好的分析,比如我就把所有写log的过程都去掉了。
3.2.1ngx_create_pool
创建一个内存池
ngx_pool_t*ngx_create_poo(size_tsize)
ngx_pool_t*p;
p=(ngx_pool_t*)malloc(size);
if(!
p){
returnNULL;
}
//计算内存池的数据区域
p->
d->
last=(u_char*)p+sizeof(ngx_pool_t);
end=(u_char*)p+size;
next=NULL;
//下个内存池
failed=0;
size=size-sizeof(ngx_pool_t);
;
max=size;
//最大数据
//我现在还是是一个单一的内存池
current=p;
chain=NULL;
//只有在需要的时候才分配大的内存区域
large=NULL;
cleanup=NULL;
returnp;
}
nginx内存池的创建非常简单,申请一个size大小的内存,把它分配给ngx_poo_t。
3.2.2ngx_palloc
从内存池中分配内存.
void*ngx_palloc(ngx_pool_t*pool,size_tsize)
u_char*m;
//遍历内存池,拿出可用的内存区域
if(size<
=pool->
max){
p=pool->
current;
do{
m=p->
last;
if((size_t)(p->
end-m)>
=size){
p->
last=m+size;
//用掉了当然要改变*last了
returnm;
}
p=p->
next;
}while(p);
returnngx_palloc_block(pool,size);
//所有的内存池都已经满了,我要在当前的pool中增加一个
//申请的内存超过了内存池的大小,所以用
returnngx_palloc_large(pool,size);
这个函数从内存池用拿出内存,如果当前内存池已满,到下一个内存池,如果所有的内存池已满,增加一个新的内存池,如果申请的内存超过了内存池的最大值,从*large中分配
3.3.3
ngx_destroy_pool
内存池的销毁
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){
if(c->
handler){
c->
handler(c->
data);
}
//释放大块的内存
for(l=pool->
large;
l;
l=l->
if(l->
alloc){
free(l->
alloc);
//小块的内存,真正意义上的内存池
for(p=pool,n=pool->
/*void*/;
p=n,n=n->
free(p);
//如果当前内存池为空,之后的毕为空
if(n==NULL){
break;
销毁一个内存池其实就是干了三件事,调用清理函数,释放大块的内存,释放内存池,需要注意的
一点是在nginx中,小块内存除了在内存池被销毁的时候都是不能被释放的。
3.3.4ngx_palloc_block
前面说过,在nginx中,当内存池满了以后,会增加一个新的内存池。
这个动作就是靠ngx_palloc_block函数实现的。
staticvoid*ngx_palloc_block(ngx_pool_t*pool,size_tsize)
u_char*m;
size_tpsize;
ngx_pool_t*p,*pnew,*current;
psize=(size_t)(pool->
end-(u_char*)pool);
m=(u_char*)malloc(psize);
m){
//一个新的内存池
pnew=(ngx_pool_t*)m;
pnew->
end=m+psize;
//是不是和ngx_palloc很相似啊
m+=sizeof(ngx_pool_data_t);
current=pool->
//遍历到内存池链表的末尾
for(p=current;
p=p->
if(p->
failed++>
4){//为什么4?
推测是个经验值
current=p->
next=pnew;
pool->
current=current?
current:
pnew;
returnm;
这个函数就是申请了一块内存区域,变为一个内存池,然后把它连接到原来内存池的末尾。
Current应该指向最后一个failed>
4的内存池的后继。
3.3.5ngx_palloc_large和ngx_pfree
在nginx中,小块内存除了在内存池销毁之外是不能释放的,但是大块内存却可以,这两个函数就是用来控制大块内存的申请和释放,代码也非常简单,调用malloc申请内存,连接到ngx_pool_large_t中和调用free释放内存。
这里就不贴上代码了。
3.3.6ngx_reset_pool
voidngx_reset_pool(ngx_pool_t*pool)
ngx_pool_t*p;
//释放大内存块,小内存块只有在撤销内存池时才释放
if(l->
ngx_free(l->
//重置进程池链表中的每个进程池的可分配起始地址
for(p=pool;
p;
d.next){
d.last=(u_char*)p+sizeof(ngx_pool_t);
3.3.7ngx_destroy_pool
voidngx_destroy_pool(ngx_pool_t*pool)
//执行释放内存时的清理回调函数
if(c->
handler){
ngx_log_debug1(NGX_LOG_DEBUG_ALLOC,pool->
log,0,
"
runcleanup:
%p"
c);
c->
//释放大内存块
log,0,"
free:
l->
//释放内存池链表中的每一个内存池
d.next;
ngx_free(p);
if(n==NULL){
break;
4.小结
nginx的内存池的代码也先介绍到这里,其实nginx内存池功能强大,所以代码也比较复杂,这里只是列出了内存池的大体流程,还有很到一部分代码未列出来。
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 内存