Nginx 内存池管理
来源:互联网 发布:淘宝多少好评一个钻 编辑:程序博客网 时间:2024/06/05 14:15
主要涉及的两个文件为ngx_palloc ngx_alloc
Nginx内存池的设计十分巧妙, 可以研究一下, 以后再写代码的时候可以用上。其具体分配的每个内存块的结构如下图。那么怎么构造出这样的结构呢? 看下下面的数据结构再说。
它有两个最为重要的数据结构,如下:
其中ngx_pool_s即所谓的内存池, 他数据的具体细节可以参考注释:
typedef struct { u_char *last;//表示当前可以写的位置,当这个ngx_pool_s(即内存块)被用尽了,则end == last u_char *end; //表示这个当前内存块最后的位置 ngx_pool_t *next;//用来寻找下个内存块,当这是最后一个内存块,则next == NULL ngx_uint_t failed;// 意义不大的参数,可以忽略} ngx_pool_data_t;struct ngx_pool_s { ngx_pool_data_t d; //d的数据结构如上,用来找当前可以写的位置, size_t max;//表示当前内存最大能分配到多大 ngx_pool_t *current;// 用来表示当前内存块访问到哪个了 ngx_chain_t *chain;// 与基本内存无关,后面阐述, ngx_pool_large_t *large;// 是个链表,存储large的内存 ngx_pool_cleanup_t *cleanup;// 与基本内存无关,后面阐述,};
可能对上述的数据结构还不太了解,那么就从如何创建ngx_pool_s这个结构体的变量和创建的过程来说吧。
ngx_pool_t *pool = ngx_create_pool(1024, log);
看如下代码, 只有第一个参数1024管用,后面的log可以忽略,表示创建一个每个内存块size为1024的。
至于创建的过程看下述代码,细节如下
ngx_pool_t *ngx_create_pool(size_t size, ngx_log_t *log){ ngx_pool_t *p; p = ngx_memalign(NGX_POOL_ALIGNMENT, size, log);//分配内存为size大小的空间,并且将void *转为ngx_pool_t *,这样这块内存空间的头被ngx_pool_t占用, if (p == NULL) { return NULL; } p->d.last = (u_char *) p + sizeof(ngx_pool_t);//现在pool指向的地址更新,注意要避过ngx_pool_t的头 p->d.end = (u_char *) p + size;// 现在pool的地址空间的尾地址 p->d.next = NULL;//因为刚申请create pool后面没有后续的空间,所以为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;//当后面如果要从pool内申请的空间小于p->max就分配小空间,即本文所述, p->current = p;// 更新pool指向哪个内存块 p->chain = NULL; p->large = NULL; p->cleanup = NULL; p->log = log; return p;}
那么如何从pool内申请内存呢?
由下述三个函数完成。第一个函数前面已经讲了,没啥特别的,第二第三个函数细节请看注释吧
void *ngx_palloc(ngx_pool_t *pool, size_t size){#if !(NGX_DEBUG_PALLOC) if (size <= pool->max) { return ngx_palloc_small(pool, size, 1); }#endif return ngx_palloc_large(pool, size);}
static ngx_inline void *ngx_palloc_small(ngx_pool_t *pool, size_t size, ngx_uint_t align){ u_char *m; ngx_pool_t *p; p = pool->current; do { m = p->d.last;//找到当前pool的最后的地址 if (align) { m = ngx_align_ptr(m, NGX_ALIGNMENT);//align 一下指针,让它是NGX_ALIGNMENT的倍数 } if ((size_t) (p->d.end - m) >= size) { //判断当前pool剩余空间是不是满足, //如果满足,就更新pool当前指向的地址,并且返回这块地址, p->d.last = m + size; return m; }//如果找不到,找下一块pool p = p->d.next; } while (p);//直到最后一个pool return ngx_palloc_block(pool, size); //最后还是没找到, 就ngx_palloc_block(pool, size)}
static void *ngx_palloc_block(ngx_pool_t *pool, size_t size){ u_char *m; size_t psize; ngx_pool_t *p, *new; psize = (size_t) (pool->d.end - (u_char *) pool);//计算每次pool该分配的大小,即size m = ngx_memalign(NGX_POOL_ALIGNMENT, psize, pool->log);// 分配内存,且align一下指针,让它是NGX_POOL_ALIGNMENT的倍数 if (m == NULL) { return NULL; } new = (ngx_pool_t *) m; new->d.end = m + psize; new->d.next = NULL; new->d.failed = 0; m += sizeof(ngx_pool_data_t); m = ngx_align_ptr(m, NGX_ALIGNMENT); new->d.last = m + size;//更新一下现在内存指到哪了? for (p = pool->current; p->d.next; p = p->d.next) { if (p->d.failed++ > 4) { pool->current = p->d.next;//如果当前p->d.failed++就更新一下pool->current 变成它的next,下次找内存就从这边还是寻找。 } } p->d.next = new;//把新分配的pool挂在后面 return m;}
前面说了 alloc small的内存,但是没有说大的内存,说说alloc large的内存吧
static void *ngx_palloc_large(ngx_pool_t *pool, size_t size){ void *p; ngx_uint_t n; ngx_pool_large_t *large; p = ngx_alloc(size, pool->log);// 先分配size大小的空间 if (p == NULL) { return NULL; } n = 0;//可以 for (large = pool->large; large; large = large->next) { if (large->alloc == NULL) { large->alloc = p; return p; } if (n++ > 3) { break; } } large = ngx_palloc_small(pool, sizeof(ngx_pool_large_t), 1); //从小内存中找到ngx_pool_large_t空间大小存储large指针 if (large == NULL) { ngx_free(p); return NULL; } large->alloc = p;//在链表最后插入large large->next = pool->large; pool->large = large; return p;}
最后内存的free就比较简单了,不过值得注意的是,小内存的话就不free的,只free large的。
它变量pool->large的链表,逐一释放。如下,没有细节
ngx_int_tngx_pfree(ngx_pool_t *pool, void *p){ ngx_pool_large_t *l; for (l = pool->large; l; l = l->next) { if (p == l->alloc) { ngx_log_debug1(NGX_LOG_DEBUG_ALLOC, pool->log, 0, "free: %p", l->alloc); ngx_free(l->alloc); l->alloc = NULL; return NGX_OK; } } return NGX_DECLINED;}
最后是当程序退出时,destroy pool,也很简单,就是遍历large链表,free
根据pool_.d.next 遍历pool,释放p就可以了。
for (l = pool->large; l; l = l->next) { 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; } }
那么来说说这个ngx的内存管理的原则是,
它分而治之,小块内存和大块内存采取不同的策略
对于小块内存,不频繁清理,这样可以节省free和malloc的时间,且不容易造成内存碎片,但是程序耗费的内存可能会增大,
大块内存可以及时清理,用链表维系,不易内存泄漏
0 0
- nginx内存池管理
- nginx内存池管理
- nginx内存池管理
- Nginx 内存池管理
- Nginx 内存池管理
- nginx内存池ngx_pool_t 及内存管理
- nginx的内存池及内存管理
- nginx -- datastruct:内存管理
- nginx共享内存管理
- Nginx内存管理
- Nginx内存管理
- Nginx slab内存管理
- Nginx内存管理
- Nginx内存管理
- nginx内存管理
- Nginx内存管理详解
- nginx源码分析--内存池ngx_poll_t 内存池管理
- Nginx源码分析---内存池结构ngx_pool_t及内存管理
- poj_2586 Y2K Accounting Bug(贪心)
- CVI使用TCP/IP做客户端
- 矩阵的初等变换
- VS2010 ClickOnce部署
- Android 实现形态各异的双向侧滑菜单 自定义控件来袭
- Nginx 内存池管理
- socket
- visual studio 2015key 密匙
- C/C++的内存机制
- 深入理解自定义Annotation,实现ButterKnif小原理
- 蓝牙4.0后台运行
- 63. Unique Paths II
- Eclipse 闪退 有效的方法,
- 玩转nodeJS系列:使用原生API实现简单灵活高效的路由功能(支持nodeJs单机集群),nodeJS本就应该这样轻快