Nginx 源码分析-- 内存池(pool)的分析 三
2012-06-07 09:39
507 查看
上一篇已经通过对 ngx_palloc 这个内存池(pool)管理的核心函数--内存分配函数进行解析,我们窥探到了Nginx内存管理的主体方法还有对于大内存需求的解决之道,同时也对管理内存池的数据结构有了更深一步的认识,通过这些认识我们可以得到以下这样一张数据结构的示意图:
View Code
好了,理解了释放特殊结构体后,我们再来看 ngx_destroy_pool 就比较简单了。回顾内存池的建设过程,先建pool单元,如果有大内存需求再建large。那么注销正好相反就是。首先处理 ngx_pool_cleanup_t 的特殊需求,如果有的话然后释放分配large,最后释放pool。其中如果配置了要写的DEBUG日志的,就还对DEBUG日志进行记录。附上源码:
大家或许有点疑惑,内存真的没有泄漏了么?ngx_pool_cleanup_t 所占的内存,释放了么?答案当然是肯定的!如果有这样的疑惑,请仔细看 ngx_pool_cleanup_add 函数他给 ngx_pool_cleanup_t 分配的内存空间也是pool单元中的内存( 同样的 ngx_pool_large_t ),释放pool的时候一并释放出来。
分析到这里,Nginx内存管理机制源码的分析就基本上结束了。感慨到Nginx内存池的设计确实精美,pool单元数据结构的设计(实用)、内存分配机制(大内存特殊处理,大内存信息的结构体也在内存池中)、内存释放机制(经典的函数指针用法,很巧妙的防止内存泄漏),很多地方都可以借鉴!
在最后,我们再用一个小小的验证程序来检验我们分析出来的成果。我们在 ngx_palloc 添加上一条 printf("call ngx_palloc\n") 其他函数也添加上类似的语句,编写如下main代码:
实验结果,截图如下:
图4 Nginx内存管理机制实验截图
实验结果简单说明下:
call ngx_create_pool //创建了pool池
call ngx_palloc //分配内存,在可分配内
call ngx_palloc //分配内存,在可分配内,但pool中没有足够的内存空间
call ngx_palloc_block // 分配新的pool单元
call ngx_palloc //分配大内存
call ngx_palloc_large //调用大内存分配函数
call ngx_palloc //分配 ngx_pool_large_t 结构体空间
call ngx_pool_cleanup_add //添加释放特殊结构体的函数
call ngx_palloc //分配ngx_pool_cleanup_t 的空间
call ngx_palloc //分配函数参数的空间
call ngx_destroy_pool //内存池pool池注销
call fun //调用释放特殊结构体的函数释放
以上实验结果,完全符合我们分析Nginx内存分配机制,Nginx内存池(pool)的分析到此处就结束了。经典的内存池管理机制!
View Code
ngx_pool_cleanup_t * ngx_pool_cleanup_add(ngx_pool_t *p, size_t size) { ngx_pool_cleanup_t *c; /* 分配ngx_pool_cleanup_t 空间 */ c = ngx_palloc(p, sizeof(ngx_pool_cleanup_t)); if (c == NULL) { return NULL; } /* 分配参数空间 值得注意以上两次分配空间都是分配在POOL池中! */ if (size) { c->data = ngx_palloc(p, size); if (c->data == NULL) { return NULL; } } else { c->data = NULL; } c->handler = NULL; c->next = p->cleanup; p->cleanup = c; ngx_log_debug1(NGX_LOG_DEBUG_ALLOC, p->log, 0, "add cleanup: %p", c); return c; }
好了,理解了释放特殊结构体后,我们再来看 ngx_destroy_pool 就比较简单了。回顾内存池的建设过程,先建pool单元,如果有大内存需求再建large。那么注销正好相反就是。首先处理 ngx_pool_cleanup_t 的特殊需求,如果有的话然后释放分配large,最后释放pool。其中如果配置了要写的DEBUG日志的,就还对DEBUG日志进行记录。附上源码:
void ngx_destroy_pool(ngx_pool_t *pool) { ngx_pool_t *p, *n; ngx_pool_large_t *l; ngx_pool_cleanup_t *c; /* 处理 ngx_pool_cleanup_t 的特殊需求 */ for (c = pool->cleanup; c; c = c->next) { if (c->handler) { ngx_log_debug1(NGX_LOG_DEBUG_ALLOC, pool->log, 0, "run cleanup: %p", c); c->handler(c->data); } } /* 释放分配large */ for (l = pool->large; l; l = l->next) { ngx_log_debug1(NGX_LOG_DEBUG_ALLOC, pool->log, 0, "free: %p", l->alloc); if (l->alloc) { ngx_free(l->alloc); } } #if (NGX_DEBUG) /* * 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 /* 释放pool */ for (p = pool, n = pool->d.next; /* void */; p = n, n = n->d.next) { ngx_free(p); if (n == NULL) { break; } } }
大家或许有点疑惑,内存真的没有泄漏了么?ngx_pool_cleanup_t 所占的内存,释放了么?答案当然是肯定的!如果有这样的疑惑,请仔细看 ngx_pool_cleanup_add 函数他给 ngx_pool_cleanup_t 分配的内存空间也是pool单元中的内存( 同样的 ngx_pool_large_t ),释放pool的时候一并释放出来。
分析到这里,Nginx内存管理机制源码的分析就基本上结束了。感慨到Nginx内存池的设计确实精美,pool单元数据结构的设计(实用)、内存分配机制(大内存特殊处理,大内存信息的结构体也在内存池中)、内存释放机制(经典的函数指针用法,很巧妙的防止内存泄漏),很多地方都可以借鉴!
在最后,我们再用一个小小的验证程序来检验我们分析出来的成果。我们在 ngx_palloc 添加上一条 printf("call ngx_palloc\n") 其他函数也添加上类似的语句,编写如下main代码:
void fun(void *p) { printf("call fun\n"); } int ngx_cdecl main(int argc, char *const *argv) { ngx_pool_t *t; ngx_pool_cleanup_t *clt; void *p1,*p2,*p3; t=ngx_create_pool(512,NULL); /*创建pool*/ printf("\n"); p1=ngx_palloc(t,416); /*分配内存,在可分配内*/ printf("\n"); p2=ngx_palloc(t,216);/*分配内存,在可分配内,但pool中没有足够的内存空间*/ printf("\n"); p3=ngx_palloc(t,624);/*分配大内存*/ printf("\n"); clt=ngx_pool_cleanup_add(t, sizeof(void *));/*添加释放特殊结构体的函数*/ clt->handler=&fun; ngx_destroy_pool(t);/*pool池注销*/ printf("\n"); return 0; }
实验结果,截图如下:
图4 Nginx内存管理机制实验截图
实验结果简单说明下:
call ngx_create_pool //创建了pool池
call ngx_palloc //分配内存,在可分配内
call ngx_palloc //分配内存,在可分配内,但pool中没有足够的内存空间
call ngx_palloc_block // 分配新的pool单元
call ngx_palloc //分配大内存
call ngx_palloc_large //调用大内存分配函数
call ngx_palloc //分配 ngx_pool_large_t 结构体空间
call ngx_pool_cleanup_add //添加释放特殊结构体的函数
call ngx_palloc //分配ngx_pool_cleanup_t 的空间
call ngx_palloc //分配函数参数的空间
call ngx_destroy_pool //内存池pool池注销
call fun //调用释放特殊结构体的函数释放
以上实验结果,完全符合我们分析Nginx内存分配机制,Nginx内存池(pool)的分析到此处就结束了。经典的内存池管理机制!
相关文章推荐
- nginx源码分析—内存池结构ngx_pool_t及内存管理
- nginx源码分析—内存池结构ngx_pool_t及内存管理(精辟)
- nginx源码分析—内存池结构ngx_pool_t及内存管理
- nginx源码分析—内存池结构ngx_pool_t及内存管理
- Nginx 源码分析-- 内存池(pool)的分析 二
- nginx源码分析—内存池结构ngx_pool_t及内存管理
- nginx源码分析—内存池结构ngx_pool_t及内存管理
- nginx源码分析—内存池结构ngx_pool_t及内存管理
- Nginx源码分析---内存池结构ngx_pool_t及内存管理
- Nginx源码分析(3)之——内存池(ngx_pool_t)分析
- Nginx 源码分析-- 内存池(pool)的分析 一
- nginx源码分析—内存池结构ngx_pool_t及内存管理
- Nginx 内存池(pool)分析
- 菜鸟nginx源码剖析数据结构篇(九) 内存池ngx_pool_t
- Nginx源码分析-内存池
- Nginx高级数据结构源码分析(四)-----内存池
- Nginx源码分析-内存池
- nginx源码分析--内存池ngx_poll_t 内存池管理
- Nginx源码分析——ngx_pool_t内存池
- Nginx 内存池(pool)分析