概述 Nginx在大多数涉及到内存使用的地方都用到了ngx_pool_t
这个结构体以及和这个结构体相关的一些函数。这个结构体是Nginx用来管理内存的用的,涉及到内存的申请、释放以及一些相关资源的管理。当我们需要去和内存打交道的时候,不需要去花费时间在担心某块内存没有释放造成野指针的情况。
Nginx在内存管理中将内存分为两种类型,一种是小块内存,一种是大块内存。这两种内存以ngx_pool_s
结构体中max
作为区分界限。其中小块内存是在内存池的数据块(对应结构体中的d
)中进行分配,在大部分情况下的小块内存的分配过程中,只需要去移动一个内部的指针便可。在分配大块内存的过程中,每次都会去申请一块内存。因此对比来看,小块内存的申请效率更加方便。具体内容可以参考源码中src/core/ngx_palloc.h|.c
的相关内容。
数据结构定义 需释放资源 需释放资源结构体ngx_pool_cleanup_t
主要管理一些需要释放的资源,比如关闭文件,删除文件等。作为ngx_pool_t
中cleanup
链表的节点类型。
1 2 3 4 5 6 7 8 9 typedef void (*ngx_pool_cleanup_pt) (void *data) ;typedef struct ngx_pool_cleanup_s ngx_pool_cleanup_t ;struct ngx_pool_cleanup_s { ngx_pool_cleanup_pt handler; void *data; ngx_pool_cleanup_t *next; };
大块内存 大块内存ngx_pool_large_t
是Nginx的内存池中的一种内存类型,当在需要分配超过一定大小的内存时会发挥作用。
1 2 3 4 5 6 7 typedef struct ngx_pool_large_s ngx_pool_large_t ;struct ngx_pool_large_s { ngx_pool_large_t *next; void *alloc; };
数据块 数据块ngx_pool_data_t
是内存池中实际分配内存的地方,这个地方主要是分配小内存,有一点需要注意的是大块内存节点的空间(ngx_pool_large_t
)也是在这里申请的。
1 2 3 4 5 6 typedef struct { u_char *last; u_char *end; ngx_pool_t *next; ngx_uint_t failed; } ngx_pool_data_t ;
内存池 内存池ngx_pool_t
是Nginx中用来管理内存的入口
1 2 3 4 5 6 7 8 9 10 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 ; };
相关操作 ngx_create_pool 创建一个size大小的内存池
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 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; }
ngx_destroy_pool 销毁内存池
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 void ngx_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) { ngx_log_debug1(NGX_LOG_DEBUG_ALLOC, pool->log , 0 , "run cleanup: %p" , c); c->handler(c->data); } } #if (NGX_DEBUG) for (l = pool->large; l; l = l->next) { ngx_log_debug1(NGX_LOG_DEBUG_ALLOC, pool->log , 0 , "free: %p" , l->alloc); } for (p = pool, n = pool->d.next; ; 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 for (l = pool->large; l; l = l->next) { if (l->alloc) { ngx_free(l->alloc); } } for (p = pool, n = pool->d.next; ; p = n, n = n->d.next) { ngx_free(p); if (n == NULL ) { break ; } } }
ngx_reset_pool 重置内存池
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 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); } } for (p = pool; p; p = p->d.next) { p->d.last = (u_char *) p + sizeof (ngx_pool_t ); p->d.failed = 0 ; } pool->current = pool; pool->chain = NULL ; pool->large = NULL ; }
ngx_palloc 申请size大小的内存并对其
1 2 3 4 5 6 7 8 9 10 11 12 13 14 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); }
ngx_pnalloc 申请size大小内存不对其
1 2 3 4 5 6 7 8 9 10 11 12 void *ngx_pnalloc(ngx_pool_t *pool, size_t size) { #if !(NGX_DEBUG_PALLOC) if (size <= pool->max) { return ngx_palloc_small(pool, size, 0 ); } #endif return ngx_palloc_large(pool, size); }
ngx_palloc_small 申请小块内存
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 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; if (align) { m = ngx_align_ptr(m, 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); }
ngx_palloc_block 申请一个新的内存池,其实是一个数据块。因为Nginx是以链表的形式去管理内存的,无论是在小块内存还是大块内存的分配上。数据块结构体ngx_pool_data_t
的next
是一个ngx_pool_t
类型的指针,当现有内存池的数据块剩余空间不够的时候,我们需要去创建一个新的ngx_pool_t
结构体来挂在当前数据块的next
下,而这个新的ngx_pool_t
结构体d
后面的所有字段值都是和之前内存池里面的值相同的。为了节约内存,因此在这个方法里面,我们会看到申请挂载的ngx_pool_t
结构体的可分配起始位置是在申请内存返回地址的基础上加上的ngx_pool_data_t
的大小,和创建的时候加上ngx_pool_t
的大小不一样。具体可以参照下面的示意图。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 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); m = ngx_memalign(NGX_POOL_ALIGNMENT, psize, pool->log ); 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.next = new ; return m; }
ngx_palloc_large 申请大块内存
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 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 ); 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 ); if (large == NULL ) { ngx_free(p); return NULL ; } large->alloc = p; large->next = pool->large; pool->large = large; return p; }
ngx_pmemalign 申请大块内存并对其
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 void *ngx_pmemalign(ngx_pool_t *pool, size_t size, size_t alignment) { void *p; ngx_pool_large_t *large; p = ngx_memalign(alignment, size, pool->log ); if (p == NULL ) { return NULL ; } large = ngx_palloc_small(pool, sizeof (ngx_pool_large_t ), 1 ); if (large == NULL ) { ngx_free(p); return NULL ; } large->alloc = p; large->next = pool->large; pool->large = large; return p; }
ngx_pfree 释放内存池中的某一个大块内存
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 ngx_int_t ngx_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; }
ngx_pcalloc 在内存池中申请内存并清零
1 2 3 4 5 6 7 8 9 10 11 12 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; }
资源相关操作 剩下的就是一些和资源相关的函数了,这类就不再一一详细的解读了。
1 2 3 4 ngx_pool_cleanup_t *ngx_pool_cleanup_add (ngx_pool_t *p, size_t size) ;void ngx_pool_run_cleanup_file (ngx_pool_t *p, ngx_fd_t fd) ;void ngx_pool_cleanup_file (void *data) ;void ngx_pool_delete_file (void *data) ;