nginx基础设施
内存池
简介:
Nginx里内存的使用大都十分有特色:申请了永久保存,抑或伴随着请求的结束而全部释放,还有写满了缓冲再从头接着写.这么做的原因也主要取决于Web Server的特殊的场景,内存的分配和请求相关,一条请求处理完毕,即可释放其相关的内存池,降低了开发中对内存资源管理的复杂度,也减少了内存碎片的存在.
所以在Nginx使用内存池时总是只申请,不释放,使用完毕后直接destroy整个内存池.我们来看下内存池相关的实现。
结构:
- struct ngx_pool_s {
- ngx_pool_data_t d;
- size_t max;
- ngx_pool_t *current;
- ngx_chain_t *chain;
- ngx_pool_large_t *large;
- ngx_pool_cleanup_t *cleanup;
- ngx_log_t *log;
- };
- struct ngx_pool_large_s {
- ngx_pool_large_t *next;
- void *alloc;
- };
- typedef struct {
- u_char *last;
- u_char *end;
- ngx_pool_t *next;
- ngx_uint_t failed;
- } ngx_pool_data_t;
实现:
这三个数据结构构成了基本的内存池的主体.通过ngx_create_pool可以创建一个内存池,通过ngx_palloc可以从内存池中分配指定大小的内存。
- 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);
- 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;
- }
这里首申请了一块大小为size的内存区域,其前sizeof(ngx_pool_t)字节用来存储ngx_pool_t这个结构体自身自身.所以若size小于sizeof(ngx_pool_t)将会有coredump的可能性。
我们常用来分配内存的有三个接口:ngx_palloc,ngx_pnalloc,ngx_pcalloc。
分别来看下它们的实现:
- 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);
- if ((size_t) (p->d.end - m) >= size) {
- p->d.last = m + size;
- return m;
- }
- p = p->d.next;
- } while (p);
- return ngx_palloc_block(pool, size);
- }
- return ngx_palloc_large(pool, size);
- }
- void *
- ngx_pnalloc(ngx_pool_t *pool, size_t size)
- {
- u_char *m;
- ngx_pool_t *p;
- if (size <= pool->max) {
- p = pool->current;
- do {
- m = p->d.last;
- if ((size_t) (p->d.end - m) >= size) {
- p->d.last = m + size;
- return m;
- }
- p = p->d.next;
- } while (p);
- return ngx_palloc_block(pool, size);
- }
- return ngx_palloc_large(pool, size);
- }
- void *
- ngx_pcalloc(ngx_pool_t *pool, size_t size)
- {
- void *p;
- p = ngx_palloc(pool, size);
- if (p) {
- ngx_memzero(p, size);
- }
- return p;
- }
ngx_pcalloc其只是ngx_palloc的一个封装,将申请到的内存全部初始化为0。
ngx_palloc相对ngx_pnalloc,其会将申请的内存大小向上扩增到NGX_ALIGNMENT的倍数,以方便内存对齐,减少内存访问次数。
Nginx的内存池不仅用于内存方面的管理,还可以通过ngx_pool_cleanup_add
来添加内存池释放时的回调函数,以便用来释放自己申请的其他相关资源。
从代码中可以看出,这些由自己添加的释放回调是以链表形式保存的,也就是说你可以添加多个回调函数来管理不同的资源。