Nginx学习(20)—内存池创建
来源:互联网 发布:怎样做好淘宝网店 编辑:程序博客网 时间:2024/06/05 19:42
内存池创建
对于内存池的结构,我们可以暂且将其分为头部以及数据域两部分,代码如下:
- struct ngx_pool_s {
- ngx_pool_data_t d; // 数据域部分,小块内存在此分配
- size_t max; // 整个数据块的大小,亦即能够分配的小块内存最大值
- ngx_pool_t *current; // 指向当前内存池
- ngx_chain_t *chain; // 可以挂载一个chain结构
- ngx_pool_large_t *large; // 当分配的内存超过max值时,即分配大块内存时,使用该成员,属于数据域部分
- 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_pool_t *
- ngx_create_pool(size_t size, ngx_log_t *log)
- {
- ngx_pool_t *p;
- /* 创建数据域大小为size的内存池,地址以NGX_POOL_ALIGNMENT对齐,这里是16位 */
- p = ngx_memalign(NGX_POOL_ALIGNMENT, size, log);
- if (p == NULL) {
- return NULL;
- }
- p->d.last = (u_char *) p + sizeof(ngx_pool_t);
- p->d.end = (u_char *) p + size;
- p->d.next = NULL;
- p->d.failed = 0;
- size = size - sizeof(ngx_pool_t);
- p->max = (size < NGX_MAX_ALLOC_FROM_POOL) ? size : NGX_MAX_ALLOC_FROM_POOL;
- p->current = p;
- p->chain = NULL;
- p->large = NULL;
- p->cleanup = NULL;
- p->log = log;
- return p;
- }
内存池分配
nginx提供给用户使用的内存分配接口有:- void *ngx_palloc(ngx_pool_t *pool, size_t size);
- void *ngx_pnalloc(ngx_pool_t *pool, size_t size);
- void *ngx_pcalloc(ngx_pool_t *pool, size_t size);
- void *ngx_pmemalign(ngx_pool_t *pool, size_t size, size_t alignment);
以ngx_palloc为例详细说明下:
- void *
- ngx_palloc(ngx_pool_t *pool, size_t size)
- {
- u_char *m;
- ngx_pool_t *p;
- /* 申请分配小内存块 */
- if (size <= pool->max) {
- p = pool->current;
- do {
- /* 内存对齐宏,下面有注释 */
- m = ngx_align_ptr(p->d.last, NGX_ALIGNMENT);
- /* 如果小内存块的数据域大于申请内存的size大小,就直接分配;
- * 否则,通过next指针寻找下一个内存池,直到找到能够分配size大小内存的内存池为止
- */
- if ((size_t) (p->d.end - m) >= size) {
- p->d.last = m + size;
- return m;
- }
- p = p->d.next;
- } while (p);
- /* 如果不存在能够分配size大小的内存池,则申请一个新的内存池,并分配。
- * failed字段在该函数里增加,一个内存池当failed字段大于4之后就将current字段指向
- * 下一个内存池,亦即当failed字段大于4之后意味着该内存池已经分配完毕。至于为什么大小
- * 是4,可能就像网站说的,是基于统计或者测试的经验吧。。
- */
- return ngx_palloc_block(pool, size);
- }
- /* 申请分配大的内存块 */
- return ngx_palloc_large(pool, size);
- }
关于内存对齐使用的宏注释:
- #define ngx_align(d, a) (((d) + (a - 1)) & ~(a - 1))
- #define ngx_align_ptr(p, a) \
- (u_char *) (((uintptr_t) (p) + ((uintptr_t) a - 1)) & ~((uintptr_t) a - 1))
以a=8为例,用二进制表示就是a = 0x1000;(a-1) = 0x00...00111,再取反后为 0x11...11000;
当d=0~8时,0 =< d+(a-1) <= 15,该数与[~(a-1)]按位与,取高位,结果为0x1000,十进制为8;
当d=9~16时,0 =< d+(a-1) <= 23,该数与[~(a-1)]按位与,取高位,结果为0x10000,十进制为16;
当d=17~24时,0 =< d+(a-1) <= 31,该数与[~(a-1)]按位与,取高位,结果为0x11000,十进制为24;
......
亦即,最后取值均为8的倍数,完成对齐的功能。
推而广之,一个数加上(a-1)后与a(2的幂)进行(a减一后取反再按位与)的操作,所得值即为这个数向上取a的整倍数。
具体的内存池分配示意图:
内存池重置
- 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) {
- if (l->alloc) {
- ngx_free(l->alloc);
- }
- }
- pool->large = NULL;
- /* 只是将last指针指向可共分配的内存的初始位置。
- * 这样,就省去了内存池的释放和重新分配操作,而达到重置内存池的目的
- */
- for (p = pool; p; p = p->d.next) {
- p->d.last = (u_char *) p + sizeof(ngx_pool_t);
- }
- }
内存池释放
- void
- ngx_destroy_pool(ngx_pool_t *pool)
- {
- ngx_pool_t *p, *n;
- ngx_pool_large_t *l;
- ngx_pool_cleanup_t *c;
- /* 先释放cleanup上挂载的数据资源,调用cleanup自身的handler处理方法 */
- 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);
- }
- }
- /* 然后释放大内存块 */
- 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);
- }
- }
- /* 最后完成内存池的释放 */
- for (p = pool, n = pool->d.next; /* void */; p = n, n = n->d.next) {
- ngx_free(p);
- if (n == NULL) {
- break;
- }
- }
- }
总结
Nginx内存的设计初探很精妙,然后学习进去发现逻辑很清晰。这种设计思想要有印象,以后遇到类似内存的设计问题可以提供备选思路。
0 0
- Nginx学习(20)—内存池创建
- nginx内存池学习
- nginx源码学习——内存池
- nginx源码学习----内存池
- nginx源码学习----内存池
- nginx源码学习----内存池
- nginx源码学习----内存池
- nginx源码学习----内存池
- nginx源码学习----内存池
- nginx源码学习----内存池
- nginx源码学习 内存池
- nginx学习——nginx中的内存池技术(与STL内存池对比分析)
- nginx源码学习1——扒内存池代码
- NGINX(1.3.7)代码学习:内存池
- nginx源代码学习系列之 [内存池]
- nginx学习_内存池ngx_pool_t
- nginx 学习四 内存池 ngx_pool_t 和内存管理操作
- nginx源码学习(二) 内存池结构 ngx_pool_t
- ZooKeeper集群安装配置
- Android开发如何双击返回键退出程序
- ubutu下调试tomcat
- ARM网络配置
- ASP写的判断Money各个位值的函数
- Nginx学习(20)—内存池创建
- CSS 布局总结——固定宽度布局
- 关于各种无法解析的外部符号问题的相应解决方案
- linux编程-守护进程编写
- 黑马程序员 《ios零基础教程》--OC语言三大特征及self和super 2014-4-25总结
- SQLite3性能优化
- 如何避免asp的SQL的执行效率低
- 20定时器
- java Socket编程总结