// src/core/ngx_palloc.h struct ngx_pool_s { ngx_pool_data_t d; size_t max; /* 全部可使用內存的大小,包含已使用和未使用內存。 區別小塊和大塊內存的標準,小于等于max為小塊內存,大于max為大塊內存。 */ ngx_pool_t *current; // 在多個ngx_pool_t連成的鏈表中,current指向分配內存時遍歷的第一個ngx_pool_t ngx_chain_t *chain; ngx_pool_large_t *large; // 指向多個ngx_pool_large_t連成的鏈表 ngx_pool_cleanup_t *cleanup; // 指向多個ngx_pool_cleanup_t連成的鏈表 ngx_log_t *log; }; typedef struct { u_char *last; // 指向未使用內存的首部 u_char *end; // 指向未使用內存的尾部 ngx_pool_t *next; // 多個ngx_pool_t通過next連成鏈表 ngx_uint_t failed; /* 每當剩余空間不足以分配出小塊內存時,failed成員就會加1。 failed成員大于4后,ngx_pool_t的current將移向下一個小塊內存池。 */ } ngx_pool_data_t; struct ngx_pool_large_s { ngx_pool_large_t *next; // 多個ngx_pool_large_t通過next連成鏈表 void *alloc; // 指向ngx_alloc分配出的大塊內存 }; struct ngx_pool_cleanup_s { ngx_pool_cleanup_pt handler; // typedef void (*ngx_pool_cleanup_pt)(void *data); void *data; ngx_pool_cleanup_t *next; // 多個ngx_pool_cleanup_t通過next連成鏈表 };
// src/core/ngx_palloc.c //創建內存池 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; // max = min{size - sizeof(ngx_pool_t), NGX_MAX_ALLOC_FROM_POOL} 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; } // 銷毀內存池 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) /* * we could allocate the pool->log from this pool * so we cannot use this log while free()ing the pool */ 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; /* 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 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; } } } // 重置內存池。把大塊內存釋放給操作系統,而小塊內存則在不釋放的情況下復用 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和ngx_pnalloc都是根據pool->max和size的大小關系,從pool中分配大小為size的內存塊。 兩者的區別在于分配小塊內存時是否對齊d.last。 */ 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); } 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); } // 分配小塊內存 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; // 遍歷ngx_pool_t鏈表,分配大小為size的小塊內存 do { m = p->d.last; if (align) { m = ngx_align_ptr(m, NGX_ALIGNMENT); // 對齊d.last } if ((size_t) (p->d.end - m) >= size) { p->d.last = m + size; return m; } p = p->d.next; } while (p); // 沒有找到大小為size的小塊內存,在鏈表尾部插入一個ngx_pool_t,分配大小為size的小塊內存 return 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); 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; // 鏈表中d.failed的值依次為6, ..., 6, 5, 4, 3, 2, 1, 0,其中current指向5 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; } // 分配大塊內存 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; } } // 沒有找到alloc為NULL的ngx_pool_large_t,從小塊內存池中分配一個新的ngx_pool_large_t large = ngx_palloc_small(pool, sizeof(ngx_pool_large_t), 1); if (large == NULL) { ngx_free(p); return NULL; } large->alloc = p; // 在鏈表頭部插入新建的ngx_pool_large_t large->next = pool->large; pool->large = large; return p; } // 這樣分配出的內存不管申請的size有多小,都是不會使用小塊內存池的,它會從進程的堆中分配內存,并掛在大塊內存組成的large單鏈表中 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; } // 釋放地址為p的大塊內存, 注意需要置alloc為NULL 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_palloc的基礎上增加了清零分配的內存 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; }