很多开源项目都有内存池,不过大多数开源项目的内存池设计都并不一样
nginx会为每一个连接创建内存池,连接断开就会释放内存池。
nginx内存池内存的分配区分大小快,代码如下
#ifndef _NGX_PALLOC_H_INCLUDED_ #define _NGX_PALLOC_H_INCLUDED_ #include3、实现细节点#include #define NGX_MAX_ALLOC_FROM_POOL (ngx_pagesize - 1) #define NGX_DEFAULT_POOL_SIZE (16 * 1024) #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) 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; }; typedef struct ngx_pool_large_s ngx_pool_large_t; struct ngx_pool_large_s { ngx_pool_large_t *next; void *alloc; }; typedef struct { u_char *last; //可以被分配的首地址 初始化p+sizeof(ngx_pool_t) u_char *end; //poll_s的末尾地址(end-待分配的空间)>last 初始化p+分配的size ngx_pool_t *next; //下一个poll块 ngx_uint_t failed;//申请内存重试失败次数,超过四次,current指向下一个节点 } ngx_pool_data_t; 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; }; typedef struct { ngx_fd_t fd; u_char *name; ngx_log_t *log; } ngx_pool_cleanup_file_t; ngx_pool_t *ngx_create_pool(size_t size, ngx_log_t *log); void ngx_destroy_pool(ngx_pool_t *pool); void ngx_reset_pool(ngx_pool_t *pool); void *ngx_palloc(ngx_pool_t *pool, size_t size); void *ngx_pnalloc(ngx_pool_t *pool, size_t size); void *ngx_pcalloc(ngx_pool_t *pool, size_t size); void *ngx_pmemalign(ngx_pool_t *pool, size_t size, size_t alignment); ngx_int_t ngx_pfree(ngx_pool_t *pool, void *p); 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); #endif
ngx_free并没有对小块进行释放,零碎的内存是相对比较耗时的(涉及list的遍历)
ngx_destroy_pool 先进行cleanup回调清理(清理红黑树或者fd等标记),然后释放所有的大小快
ngx_reset_pool 释放大块,重置小块内存进行复用,目前源码应用geo负载均衡模块
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;
}
清理cleanup
limit_conn模块中使用
static void
ngx_stream_limit_conn_cleanup(void *data)
{
ngx_stream_limit_conn_cleanup_t *lccln = data;
ngx_slab_pool_t *shpool;
ngx_rbtree_node_t *node;
ngx_stream_limit_conn_ctx_t *ctx;
ngx_stream_limit_conn_node_t *lc;
ctx = lccln->shm_zone->data;
shpool = (ngx_slab_pool_t *) lccln->shm_zone->shm.addr;
node = lccln->node;
lc = (ngx_stream_limit_conn_node_t *) &node->color;
ngx_shmtx_lock(&shpool->mutex);
ngx_log_debug2(NGX_LOG_DEBUG_STREAM, lccln->shm_zone->shm.log, 0,
"limit conn cleanup: %08Xi %d", node->key, lc->conn);
lc->conn--;
if (lc->conn == 0) {
ngx_rbtree_delete(ctx->rbtree, node);
ngx_slab_free_locked(shpool, node);
}
ngx_shmtx_unlock(&shpool->mutex);
}



