nginx 内存池
来源:互联网 发布:python俄罗斯方块 编辑:程序博客网 时间:2024/05/23 01:18
nginx的设计思想是小块内存用自己的内存池pool分配,大块内存用malloc分配,并且大块内存和小块内存的管理结构都存储在pool中,由他们管理.
nginx采用多次分配,一次释放,即一次connect或request完成后,大块小块内存一同释放.
看一下内存池的基本数据结构:struct ngx_pool_large_s { ngx_pool_large_t *next; void *alloc; //指向大块内存};
typedef struct { u_char *last; //当前内存分配的结束位置,即下一段可分配内存的起始位置 u_char *end; //内存池的结束位置 ngx_pool_t *next; //连接到下一个内存池 ngx_uint_t failed; //记录内存分配失败的次数} 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){ ngx_pool_t *p; //内存分配函数,分配大小为size,返回指针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); //设置max.(比max大的是大内存块.) 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;}
//销毁内存池.内存池销毁后就完全不存在了.voidngx_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); } } //销毁大块内存 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); } }#if (NGX_DEBUG) /* * we could allocate the pool->log from this pool * 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 //销毁内存池 for (p = pool, n = pool->d.next; /* void */; p = n, n = n->d.next) { ngx_free(p); if (n == NULL) { break; } }}
//重置内存池,重置后会内存池链表中数据区都为空,即可用.voidngx_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); } } pool->large = NULL; //将每块pool的last指向数据区的起始位置 for (p = pool; p; p = p->d.next) { p->d.last = (u_char *) p + sizeof(ngx_pool_t); }}
//分配内存池,从内存池链表中找到一块内存,交给用户void *ngx_palloc(ngx_pool_t *pool, size_t size){ u_char *m; ngx_pool_t *p; if (size <= pool->max) { //申请小块内存 p = pool->current; do { m = ngx_align_ptr(p->d.last, NGX_ALIGNMENT); if ((size_t) (p->d.end - m) >= size) { p->d.last = m + size; return m; } p = p->d.next; } while (p); //由于已有的内存块不够,另外开辟一块新pool return ngx_palloc_block(pool, size); } //申请大块内存 return ngx_palloc_large(pool, size);}
//和上一个函数一样,只不过没有进行对齐设置void *ngx_pnalloc(ngx_pool_t *pool, size_t size){ u_char *m; ngx_pool_t *p; if (size <= pool->max) { 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); } return ngx_palloc_large(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, *current; 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; current = pool->current; //是指pool的current为最后一个failed大于4的内存块. /* 我们仔细看一下代码,p->d.failed++是持续的, 即后面pool中的failed肯定>=前面的failed 所以这里的"最后一个failed大于4"一定表示前面的都大于4 所以current指向第一个failed小于4的pool内存块 **/ for (p = current; p->d.next; p = p->d.next) { if (p->d.failed++ > 4) { current = p->d.next; } } p->d.next = new; pool->current = current ? current : new; return m;}
申请一个新的内存块,申请并挂接到内存池链表中后如图:
//分配大的内存块,直接用malloc.大块内存的管理结构存储在pool中的数据区.static void *ngx_palloc_large(ngx_pool_t *pool, size_t size){ void *p; ngx_uint_t n; ngx_pool_large_t *large; //用malloc申请内存 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; } }//没找到一个可用的大块内存管理结构,//那么在pool池中申请一块内存用于存储该管理结构 large = ngx_palloc(pool, sizeof(ngx_pool_large_t)); if (large == NULL) { ngx_free(p); return NULL; }//将该管理结构链入large中//每次新申请的大块内存管理结构总是插入链表的前面. large->alloc = p; large->next = pool->large; pool->large = large; return p;}
解析一下上图:
1.大块内存管理结构存放在pool池中.
2.大块内存的数据区是malloc开辟出来的,不在pool池中.
3.大块内存管理结构是一个链表,将所有大块内存管理结构都连接起来.
//创建大块内存,并挂载到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; }// 在pool的数据区创建大块内存管理结构 large = ngx_palloc(pool, sizeof(ngx_pool_large_t)); if (large == NULL) { ngx_free(p); return NULL; }//将大块内存的管理结构挂载到large链表中 large->alloc = p; large->next = pool->large; pool->large = large; return p;}
//释放大内存块ngx_int_tngx_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函数ngx_pool_cleanup_t *ngx_pool_cleanup_add(ngx_pool_t *p, size_t size){ ngx_pool_cleanup_t *c;//在pool池的数据区中创建cleanup管理结构 c = ngx_palloc(p, sizeof(ngx_pool_cleanup_t)); if (c == NULL) { return NULL; }//在pool池的数据区中分配cleanup的数据 if (size) { c->data = ngx_palloc(p, size); if (c->data == NULL) { return NULL; } } else { c->data = NULL; }//将新分配的cleanup节点链入cleanup链表中 c->handler = NULL; c->next = p->cleanup;//注册cleanup函数 p->cleanup = c; ngx_log_debug1(NGX_LOG_DEBUG_ALLOC, p->log, 0, "add cleanup: %p", c); return c;}
//关闭cleanup中的文件描述字voidngx_pool_run_cleanup_file(ngx_pool_t *p, ngx_fd_t fd){ ngx_pool_cleanup_t *c; ngx_pool_cleanup_file_t *cf; //调用ngx_pool_cleanup_file (就是关闭文件描述字) for (c = p->cleanup; c; c = c->next) { if (c->handler == ngx_pool_cleanup_file) { cf = c->data; if (cf->fd == fd) { c->handler(cf); c->handler = NULL; return; } } }}
//cleanup结构体typedef struct { ngx_fd_t fd; //文件描述字 u_char *name; //名称 ngx_log_t *log; } ngx_pool_cleanup_file_t;
nginx的内存池释放
nginx只提供给了用户申请内存的接口,却没有释放内存的接口,那么nginx是如何完成内存释放的呢?总不能一直申请,用不释放啊。针对这个问题,nginx利用了web server应用的特殊场景来完成.
一个web server总是不停的接受connection和request,所以nginx就将内存池分了不同的等级,有进程级的内存池、connection级的内存池、request级的内存池。每次创建一个内存池链表,每个内存池链表中所有内存池节点大小都是相等的,但是不同的链表中链表节点可能不同.也就是说,创建好一个worker进程的时候,同时为这个worker进程创建一个内存池,待有新的连接到来后,就在worker进程的内存池上为该连接创建起一个内存池;连接上到来一个request后,又在连接的内存池上为request创建起一个内存池。
这样,在request被处理完后,就会释放request的整个内存池,连接断开后,就会释放连接的内存池。因而,就保证了内存有分配也有释放。
- nginx内存池管理
- nginx中的内存池
- [zz] nginx 内存池
- nginx内存池管理
- nginx中的内存池
- nginx中的内存池
- nginx内存池管理
- nginx 内存池
- Nginx内存池
- NGINX 内存池
- nginx内存池
- nginx内存池学习
- Nginx 内存池管理
- nginx 内存池
- nginx中的内存池
- nginx-----内存池
- Nginx 内存池
- Nginx 内存池管理
- 有两种常见的情况充斥着SEO优化市场,让排名得不到稳定
- 今日问题总结
- ace_time
- tomcat设置URL编码
- c# ascii转换方法
- nginx 内存池
- 背景图片自适应浏览器大小
- Win7+64位操作系统成功注册dll的方法!(已测试成功)
- 如何成为优秀的游戏测试工程师——Do Better
- 了解mongodb应用场景、限制及实践
- MTK Android 之MT6577驱动笔记
- java 搜索
- 转载---XCode Debugger中的Icon符号的意义
- 那些年,哥私藏的源代码