the use of memory pools brings many benefits to nginx, such as ease of use of memory, simplification of logic code, and improvement of program performance.
Several key points of knowledge are listed below:
(1) function Ngx_palloc () when trying to allocate size memory from memory, in two cases, a size smaller than Pool->max, called a small block memory allocation, if the current memory pool node is smaller than size, then request a new equivalent size memory pool node, Then allocate a size memory space from this new memory pool node. If the size is greater than Pool->max, the large chunk of memory is allocated, and the function that is called immediately requests large chunks of memory from the operating system.
(2) The application of the small block memory is inserted in the tail node of the linked list, while the new chunk memory is inserted in front of the linked list.
(3) Nginx only provides the release of large chunks of memory, does not provide the release of small chunks of memory, meaning that the memory allocated from the memory pool will not be back to the memory pool, and only when the entire memory pool is destroyed, the memory will be recycled into the system memory.
(4) Current field in ngx_pool_t: This field records the starting node for allocating memory from the memory pool, and nginx specifies that when the total number of failed allocations for a memory node is greater than or equal to 6, current points to the next memory node.
(5) Why the maximum value of the Pool->max field is limited to one page of memory, which is also the critical of small chunks of memory and large chunks of memory, because only if the allocated space is less than one page is necessary to cache, otherwise it is not as good as directly using the System interface malloc () to the operating system application.
Definitions of individual structures:
Bulk memory management structure struct ngx_pool_large_s { ngx_pool_large_t *next; Connect the next large memory management void *alloc; The large memory address of the application }; Data Management typedef struct { U_char *last in memory pool ; The starting address of the available memory U_char *end; The end address of the available memory ngx_pool_t *next; Points to the next memory pool node ngx_uint_t failed;//application, the number of failures } ngx_pool_data_t; Memory Pool struct ngx_pool_s { ngx_pool_data_t D; Store data size_t max; The available memory size for the data, up to 1 pages ngx_pool_t *current;//points to memory pool ngx_chain_t *chain allocated memory ; ngx_pool_large_t *large; Connect large memory management structure ngx_pool_cleanup_t *cleanup; Clean Object Head ngx_log_t *log; };
Initialization of the memory pool:
Create a memory pool of size 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); Applies a size byte memory if (p = = null) { return null; } P->d.last = (U_char *) p + sizeof (ngx_pool_t); Point to the available memory start address p->d.end = (U_char *) p + size; Point to the end address of available memory p->d.next = NULL; Initially, the next available memory is null p->d.failed = 0; The memory request failed 0 times size = size-sizeof (ngx_pool_t); The actual available size, minus the size of the control structure P->max = (Size < Ngx_max_alloc_from_pool)? Size:ngx_max_alloc_from_pool; The maximum can only be one page size p->current = p; Point to the memory pool that is allocating memory p->chain = NULL; P->large = NULL; P->cleanup = NULL; P->log = log; return p; }
Destruction and reset of the memory pool:
Destroy memory pool void Ngx_destroy_pool (ngx_pool_t *pool) {ngx_pool_t *p, *n; ngx_pool_large_t *l; ngx_pool_cleanup_t *c; Run Cleanup Object handler for (c = pool->cleanup; C; c = c->next) {if (C->handler) {Ngx_log_d EBUG1 (Ngx_log_debug_alloc, Pool->log, 0, "Run Cleanup:%p", c); C->handler (C->data); }}//Free large memory 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); Use free to release malloc request Memory}} #if (Ngx_debug)/* * We could allocate the pool->log from this P Ool * 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//releases each requested memory pool object ngx_pool_t for (p = pool, n = pool->d.next;/* void */; p = n, n = n-> D.next) {ngx_free (P); if (n = = NULL) {break; }}}//reset memory pool void Ngx_reset_pool (ngx_pool_t *pool) {ngx_pool_t *p; ngx_pool_large_t *l; Free large memory for (L = pool->large; l; l = l->next) {if (L->alloc) {ngx_free (l->alloc); }}//Memory pool object, only change last pointer position for (p = pool; p; p = p->d.next) {p->d.last = (U_char *) p + sizeof (ngx_pool_t); Causes all memory pool objects to have the same starting address offset for the available memory p->d.failed = 0; } pool->current = pool; Pool->chain = NULL; Pool->large = NULL; }
Allocating memory:
Allocate memory (address alignment) void * Ngx_palloc (ngx_pool_t *pool, size_t size) {U_char *m; ngx_pool_t *p; if (size <= Pool->max) {//Small memory request, with size as standard p = pool->current; do {m = Ngx_align_ptr (P->d.last, ngx_alignment);//D.last address is aligned first if (size_t) (p->d.end -m) >= size) {//available memory is greater than the memory to be requested P->d.last = m + size; Direct update d.last return m; Direct return} p = p->d.next; Otherwise, find the next available memory pool object} while (p); If not found, then to request a new memory pool object return Ngx_palloc_block (pool, size); } return Ngx_palloc_large (pool, size); Large memory Request processing}//Allocate memory (address can not be aligned) void * NGX_PNALLOC (ngx_pool_t *pool, size_t size) {U_char *m; ngx_pool_t *p; if (size <= Pool->max) {//small memory 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); Request a new memory pool object} return Ngx_palloc_large (pool, size); Large Memory}
Small Block memory allocation:
//request a new memory pool object 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); The total size of the application memory M = ngx_memalign (Ngx_pool_alignment, psize, Pool->log); Alignment request Memory if (M = = null) {return null; } new = (ngx_pool_t *) m; New Memory New->d.end = m + psize; The last address of the available memory New->d.next = NULL; new->d.failed = 0; m + = sizeof (ngx_pool_data_t); There is only one ngx_pool_data_t, saving the rest of the ngx_pool_t overhead m = ngx_align_ptr (M, ngx_alignment); New->d.last = m + size; The starting address of the available memory//If the current number of failed requests for memory has been 5 times, for the 6th time, it will point to the new memory pool object 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; Connect the memory pool object that just requested return m; }
Bulk memory allocation
Large memory request processing 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); Direct malloc requests Memory if (p = = null) { return null; } n = 0; for (large = pool->large; large; large = Large->next) { if (Large->alloc = = NULL) { ////If memory is freed, re-usable
large->alloc = p; return p; } if (n++ > 3) { //But only 4 times, 5th Direct break, create large memory management structure break ; } } Large = Ngx_palloc (pool, sizeof (ngx_pool_large_t)); Request memory from the memory pool object if (large = = NULL) { ngx_free (p); return NULL; } Large->alloc = p; Large memory point to request //Insert Large header Large->next = pool->large; Pool->large = large; return p; }
Allocating memory directly:
Request Memory void * ngx_pmemalign (ngx_pool_t *pool, size_t size, size_t alignment) { void), no matter how large the memory size is *p; ngx_pool_large_t *large; p = ngx_memalign (alignment, size, pool->log); The requested Memory if (p = = null) { return null; } Large = Ngx_palloc (pool, sizeof (ngx_pool_large_t)); Request a large memory management structure if (large = = NULL) { ngx_free (p); return NULL; } Put into the memory pool ngx_pool_t manage large->alloc = p; Point to request memory //insert to head Large->next = pool->large; Pool->large = large; return p; }
Free Memory:
Free memory ngx_int_t ngx_pfree (ngx_pool_t *pool, void *p) { ngx_pool_large_t *l; Release only large memory for (L = pool->large; l; l = l->next) { if (p = = l->alloc) { ngx_log_debug1 (ngx_log_debug_al LOC, Pool->log, 0, "Free:%p", l->alloc); Ngx_free (l->alloc); L->alloc = NULL; Empty return NGX_OK; } } return ngx_declined; }
Copyright NOTICE: This article for Bo Master original article, without Bo Master permission not reproduced.
The above describes the Nginx high-level data structure source analysis (iv)-----memory pool, including aspects of the content, I hope to be interested in PHP tutorial friends helpful.