Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

Analysis of nginx memory Pool Source Code

2025-01-31 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/02 Report--

This article focuses on "nginx memory pool source code analysis", interested friends may wish to take a look. The method introduced in this paper is simple, fast and practical. Next let the editor to take you to learn "nginx memory pool source code analysis" it!

Overview of memory Pool

A memory pool is a pre-request to allocate a certain number of equal-sized (usually) blocks of memory for reserve before the actual use of memory. When there is a new memory requirement, part of the memory block is allocated from the memory pool, and if the memory block is insufficient, continue to apply for new memory.

The advantages of memory pool include reducing the time cost of applying for and releasing memory from the system, solving the fragmentation caused by frequent memory allocation, prompting program performance, reducing programmers' attention to memory when writing code, and so on.

At present, some common memory pool implementation schemes include the memory allocation area in STL, the open source project TCMalloc of ngx_pool_t,google in object_pool,nginx in boost, and so on.

1. Nginx data structure / / SGI STL demarcation point between small and large memory: 128B// nginx (allocating memory to all modules of the HTTP server) demarcation point between small and large memory: 4096B#define NGX_MAX_ALLOC_FROM_POOL (ngx_pagesize-1) / / memory pool default size # define NGX_DEFAULT_POOL_SIZE (16 * 1024) / / memory pool byte alignment SGI STL is 8B#define NGX_POOL_ALIGNMENT 16#define NGX_MIN_POOL_SIZE ngx_align ((sizeof (ngx_pool_t) + 2 * sizeof (ngx_pool_large_t)),\ NGX_POOL_ALIGNMENT) / / adjust the open memory to an integer multiple of 16 # define ngx_align (d) A) ((d) + (a-1)) & ~ (a-1)) typedef struct ngx_pool_s ngx_pool_t Typedef struct {u_char * last; / / points to the starting address of available memory u_char * end; / / points to the end address of available memory ngx_pool_t * next; / / points to the next memory block ngx_uint_t failed / / number of space allocation failures in current memory blocks} the type of ngx_pool_data_t;// memory pool block struct ngx_pool_s {ngx_pool_data_t d; / / memory pool header information size_t max; ngx_pool_t * current; / / points to the memory block that can be used to allocate space (failed)

< 4)的起始地址 ngx_chain_t *chain; // 连接所有的内存池块 ngx_pool_large_t *large; // 大块内存的入口指针 ngx_pool_cleanup_t *cleanup; // 内存池块的清理操作,用户可设置回调函数,在内存池块释放之前执行清理操作 ngx_log_t *log; // 日志}; 二、nginx向OS申请空间ngx_create_pool// 根据size进行内存开辟ngx_pool_t * ngx_create_pool(size_t size, ngx_log_t *log){ ngx_pool_t *p; // 根据系统平台定义的宏以及用户执行的size,调用不同平台的API开辟内存池 p = ngx_memalign(NGX_POOL_ALIGNMENT, size, log); if (p == NULL) { return NULL; } p->

D.last = (u_char *) p + sizeof (ngx_pool_t); / / points to the starting address of available memory p-> d.end = (u_char *) p + size; / / points to the end address of available memory p-> d.next = NULL / / points to the next memory block, which has just been applied for, so leave blank p-> d.failed = 0; / / whether the memory block has been successfully opened size = size-sizeof (ngx_pool_t) / / available space = total space-header information / / use a page if the specified size is greater than one page, otherwise use the specified size / / max = min (size, 4096). Max refers to the size of the block of memory other than the beginning information, p-> max = (size)

< NGX_MAX_ALLOC_FROM_POOL) ? size : NGX_MAX_ALLOC_FROM_POOL; p->

Current = p; / / points to the starting address of the memory block that can be used to allocate space, p-> chain = NULL; p-> large = NULL; / / A small block of memory is opened up directly, and there is a memory opening p-> cleanup = NULL; p-> log = log; return p;} pointed to by large in the large block.

3. Nginx applies for space void * ngx_palloc (ngx_pool_t * pool, size_t size) {# if! (NGX_DEBUG_PALLOC) if (size max) {/ / currently allocated space is less than max, small blocks of memory allocation return ngx_palloc_small (pool, size, 1); / / consider memory alignment} # endif return ngx_palloc_large (pool, size) } void* ngx_pnalloc (ngx_pool_t * pool, size_t size) {# if! (NGX_DEBUG_PALLOC) if (size max) {return ngx_palloc_small (pool, size, 0); / / No memory alignment} # endif return ngx_palloc_large (pool, size);} void* ngx_pcalloc (ngx_pool_t * pool, size_t size) {void* p; p = ngx_palloc (pool, size) / / consider memory alignment if (p) {ngx_memzero (p, size); / / memory can be initialized to 0} return p;}

Ngx_palloc_small has high allocation efficiency and only makes pointer offset.

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; / / allocate from the memory pool pointed to by the current pointer of the first memory block p = pool- > current; do {m = p-> d.last / / m points to the starting address of allocable memory if (align) {/ / adjust m to NGX_ALIGNMENT integer multiple m = ngx_align_ptr (m, NGX_ALIGNMENT) } / / the core code for memory allocation in the memory pool if ((size_t) (p-> d.end-m) > = size) {/ / if space is available > = requested space / / offset d.last pointer, record the first address of free space p-> d.last = m + size; return m } / / there is not enough free space in the current memory block. If there is a next memory block, it will move to the next memory block / / if not, p will be left empty and exit while p = p-> d.next.} while (p); return ngx_palloc_block (pool, size);}

There are enough blocks in the current memory pool to allocate:

The current memory pool does not have enough blocks to allocate:

Open up new memory blocks and modify last, end, next, failed of new memory block information

Failed++ of all previous memory blocks

Connect the new memory block and the previous memory block

Static void * ngx_palloc_block (ngx_pool_t * pool, size_t size) {u_char * m; size_t psize; ngx_pool_t * p, * new; / / opens up a memory block of the same size as the previous block psize = (size_t) (pool- > d.end-(u_char *) pool) / / after aligning psize to an integral multiple of NGX_POOL_ALIGNMENT, apply for space m = ngx_memalign (NGX_POOL_ALIGNMENT, psize, pool- > log) from OS; if (m = = NULL) {return NULL;} new = (ngx_pool_t *) m; / / point to the starting address of the newly opened memory block new- > d.end = m + psize / / the address at the end of the newly opened memory block is new- > d.next = NULL; / / the address of the next memory block is NULL new- > d.failed = 0 / / the number of times the current memory block failed to allocate space / / points to the tail of the header information, while max,current, chain, etc. only have m + = sizeof (ngx_pool_data_t) in the first memory block; m = ngx_align_ptr (m, NGX_ALIGNMENT); new- > d.last = m + size / / last points to the starting address of the free space of the current block / / because each time the space is allocated from pool- > current / / if the memory block is allocated here, except for new, all other memory blocks fail to be allocated for (p = pool- > current; p-> d.next! = NULL) P = p-> d.next) {/ / A pair of failed of all memory blocks are + + until the number of failures of the memory block allocation is greater than 4 / / it means that the remaining space of the memory block is very small and the space can no longer be allocated / / modify the current pointer. Next time, the space will be allocated from current. When re-allocating, you do not have to traverse the previous memory block if (p-> d.failedblocks + > 4) {pool- > current = p-> d.next }} p-> d.next = new; / / Connect the first memory block of allocable space and the newly opened memory block return m;}

4. Allocation and release of chunks of memory typedef struct ngx_pool_large_s ngx_pool_large_t;struct ngx_pool_large_s {ngx_pool_large_t * next; / / the starting address of the next chunk of memory void * alloc; / / the starting address of chunks of memory} Static void * ngx_palloc_large (ngx_pool_t * pool, size_t size) {void * p; ngx_uint_t n; ngx_pool_large_t * large; / / calls malloc p = ngx_alloc (size, pool- > log); if (p = = NULL) {return NULL;} n = 0 / / for loops through the linked list for (large = pool- > large; large) that stores chunks of memory information Large = large- > next) {if (large- > alloc = = NULL) {/ / when a large chunk of memory is ngx_pfree, alloc is a NULL / / ergodic linked list. If the first address of the bulk of memory is empty, the memory address of the current malloc is written to alloc large- > alloc = p; return p. } / / after 4 times of traversal, if you have not found the corresponding information of the freed chunk of memory / / in order to improve efficiency, apply for space in small chunks of memory directly to save the information of chunks of memory if (nasty + > 3) {break }} / / allocate large chunks of memory * next and * alloc on a small memory pool by pointer offset large = ngx_palloc_small (pool, sizeof (ngx_pool_large_t), 1) If (large = = NULL) {/ / if you fail to allocate * next and * alloc space on small chunks of memory, you cannot record large chunks of memory / / free chunks of memory p ngx_free (p); return NULL;} large- > alloc = p; / / alloc points to the first address large- > next = pool- > large of large chunks of memory / / these two sentences use head insertion to store the recorded information of the new memory block in the linked list with large as the node pool- > large = large; return p;}

Release of chunks of memory

/ / release ngx_int_t ngx_pfree (ngx_pool_t * pool, void * p) {ngx_pool_large_t * l; for (l = pool- > large; l) pointed to by p L = l-> next) {/ / traverses the linked list of chunks of memory information and finds the chunk of memory if corresponding to p (p = = 1-> alloc) {ngx_log_debug1 (NGX_LOG_DEBUG_ALLOC, pool- > log, 0, "free:% p", l-> alloc) / / release large chunks of memory without releasing memory space for storing information ngx_free (l-> alloc); / / free l-> alloc = NULL; / / alloc empty return NGX_OK;}} return NGX_DECLINED;} V. About small chunks of memory not being freed

Using last and end to indicate the free space, it is impossible to return the used space to the memory pool reasonably, but it will reset the memory pool. At the same time, header information pointing to large memory block large and cleanup function cleanup is also stored.

Considering the efficiency of nginx, small blocks of memory are allocated efficiently and memory is not reclaimed at the same time.

Void ngx_reset_pool (ngx_pool_t * pool) {ngx_pool_t * p; ngx_pool_large_t * l; / / because you need to reset a small block of memory, and the control information of a large block of memory is saved in a small block of memory / / so you need to release a large block of memory first and reset the small block of memory for (l = pool- > large; l). L = l-> next) {if (l-> alloc) {ngx_free (l-> alloc);}} / / traverse the linked list of small blocks of memory, reset the management information for such as last, failed, current, chain, large (p = pool; p) P = p-> d.next) {/ / because only the first memory block has management information other than ngx_pool_data_t, other memory blocks only have ngx_pool_data_t information / / will not make an error, but it will waste space p-> d.last = (u_char *) p + sizeof (ngx_pool_t); p-> d.failed = 0 } / / current points to the memory block that can be used to allocate memory pool- > current = pool; pool- > chain = NULL; pool- > large = NULL;}

Nginx is essentially a http server, which usually deals with short links and provides services indirectly. it does not require much memory, so it can be reset instead of reclaiming memory.

After the client initiates a requests request, the nginx server will return a response response when it receives the request. If the client does not receive another request within the keep-alive time, the nginx server will actively disconnect and the memory pool will be reset. The next time the client request comes again, the memory pool can be reused.

If you are dealing with long links, as long as the client is still online, the server's resources cannot be released until the system resources are exhausted. Long links generally use SGI STL memory pool to open up and release memory, but this way is less efficient than nginx in allocating and reclaiming space.

VI. Destroy and empty the memory pool

Suppose the following:

/ / assume that the memory alignment is 4Btypedef struct {char* p; char data [508];} stData;ngx_pool_t * pool = ngx_create_pool (512B, log); / / create a nginx memory block with a total space of 512B stData* data_ptr = ngx_alloc / / because the actual memory available is: 512-sizeof (ngx_pool_t), it belongs to large memory opening data_ptr- > p = malloc (10); / / p points to external heap memory, similar to the use of external resources in C++ objects

When a large chunk of memory is reclaimed, calling ngx_free will cause a memory leak.

For the above memory leak, you can release the memory by calling back the function (through the function pointer)

Typedef void (* ngx_pool_cleanup_pt) (void * data); the following structures of typedef struct ngx_pool_cleanup_s ngx_pool_cleanup_t;// are pointed to by ngx_pool_s.cleanup, and are also small chunks of memory stored in the memory pool struct ngx_pool_cleanup_s {ngx_pool_cleanup_pt handler; void * data; / / pointing to the resources to be freed ngx_pool_cleanup_t * next / / the functions for releasing resources are all placed in a linked list, and point to this list with next}

The function interface provided by nginx:

/ / p represents the entry address of the memory pool, size indicates the size of the p-> cleanup- > data pointer / / p-> cleanup points to the structure containing cleanup function information / / ngx_pool_cleanup_add returns the pointer ngx_pool_cleanup_t* ngx_pool_cleanup_add (ngx_pool_t * p, size_t size) {ngx_pool_cleanup_t* c of the structure containing cleanup function information / / Open up the structure of the cleanup function, which is actually a small piece of memory stored in the memory pool c = ngx_palloc (p, sizeof (ngx_pool_cleanup_t)); if (c = = NULL) {return NULL;} if (size) {/ / apply for size space c-> data = ngx_palloc (p, size) for c-> data If (c-> data = = NULL) {return NULL;}} else {c-> data = NULL;} c-> handler = NULL; / / string the current structure after pool- > cleanup c-> next = p-> cleanup; p-> cleanup = c; ngx_log_debug1 (NGX_LOG_DEBUG_ALLOC, p-> log, 0, "add cleanup:% p", c) Return c;}

Mode of use:

Void release (void* p) {free (p);} ngx_pool_cleanup_t* clean_ptr = ngx_clean_cleanup_add (pool, sizeof (char*)); clean_ptr- > handler = & release; / / the user sets the function clean_ptr- > data = data_ptr- > p that the user needs to call before destroying the memory pool; / / the user sets the address ngx_destroy_pool (pool) of the memory to be freed before destroying the memory pool / / user destroys memory pool 7. Compile and test memory pool interface function void ngx_destroy_pool (ngx_pool_t * pool) {ngx_pool_t * p, * n; ngx_pool_large_t * l; ngx_pool_cleanup_t * c / / traversing the cleanup linked list (functions that need to be called before releasing when storing), can release externally occupied resources 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);}} / release large chunks of memory for (l = pool- > large; l; l = 1-> next) {if (l-> alloc) {ngx_free (l-> alloc);}} / free small chunks of memory pool for (p = pool, n = pool- > d.nextt; / * void * / P = n, n = n-> d.next) {ngx_free (p); if (n = = NULL) {break;}

Execute configure to generate Makefile files (if an error is reported, apt is required to install the software)

Makefile is as follows:

Execute the make command to compile the source code using Makefile and generate .o files in the corresponding directory

# include # include void ngx_log_error_core (ngx_uint_t level, ngx_log_t * log, ngx_err_t err, const char * fmt,...) {} typedef struct Data stData;struct Data {char * ptr; FILE * pfile;}; void func1 (char * p) {printf ("free ptr mem!\ n"); free (p) } void func2 (FILE * pf) {printf ("close file!\ n"); fclose (pf);} void main () {/ / max = 512-sizeof (ngx_pool_t) / / create nginx memory blocks with a total space of 512 bytes ngx_pool_t * pool = ngx_create_pool (512, NULL); if (pool = = NULL) {printf ("ngx_create_pool fail..."); return } / / void * p1 = ngx_palloc (pool, 128) allocated from small memory pools; if (p1 = = NULL) {printf ("ngx_palloc 128 bytes fail..."); return;} / / stData * p2 = ngx_palloc (pool, 512) allocated from large memory pools If (p2 = = NULL) {printf ("ngx_palloc 512 bytes fail..."); return;} / occupies external heap memory p2-> ptr = malloc (12); strcpy (p2-> ptr, "hello world"); / / file descriptor p2-> pfile = fopen ("data.txt", "w") Ngx_pool_cleanup_t * C1 = ngx_pool_cleanup_add (pool, sizeof (char*)); C1-> handler = func1; / / set callback function C1-> data = p2-> ptr; / / set resource address ngx_pool_cleanup_t * c2 = ngx_pool_cleanup_add (pool, sizeof (FILE*)); c2-> handler = func2; c2-> data = p2-> pfile; / / 1. Call all preset cleanup functions 2. Release large chunks of memory 3. Free all memory ngx_destroy_pool (pool); return;} of the small memory pool

Because the created cleanup blocks are chained into pool- > cleanup in ngx_pool_cleanup_add, ngx_destroy_pool cleans the files first and then cleans the heap memory.

At this point, I believe that everyone on the "nginx memory pool source code analysis" have a deeper understanding, might as well to the actual operation of it! Here is the website, more related content can enter the relevant channels to inquire, follow us, continue to learn!

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report