ngxin中为了加快内存分配的速度,引入了内存池, 大块申请, 减少分配次数, 小块分割, 极大的提高了内存申请速度, 另外一个用途就是省去了很多内存管理的任务,因为这里没有提供内存释放的功能,也就是说在pool中分配的内存,只有pool被销毁的时候才能释放掉,真正的还给系统, 因此全局的pool存储的都是一些静态的不会变动的数据, 而会变动的数据都会单独创建一个pool, 用完之后释放掉pool, 也就实现了集中申请集中释放, 肯定会有浪费内存的现象存在, 和提高运行速度比起来, 浪费点内存还是可以接受的.

基本数据结构

  1. typedef struct ngx_pool_cleanup_s ngx_pool_cleanup_t;
  2. typedef struct ngx_pool_large_s ngx_pool_large_t;
  3. typedef struct ngx_pool_s ngx_pool_t;
  4. struct ngx_pool_cleanup_s {
  5. ngx_pool_cleanup_pt handler;
  6. void *data;
  7. ngx_pool_cleanup_t *next;
  8. };
  9. struct ngx_pool_large_s {
  10. ngx_pool_large_t *next;
  11. void *alloc;
  12. };
  13. typedef struct {
  14. /*使用的内存位置*/
  15. u_char *last;
  16. /*分配总的内存结束位置*/
  17. u_char *end;
  18. /*下一块内存指针*/
  19. ngx_pool_t *next;
  20. /*标记分配失败次数*/
  21. ngx_uint_t failed;
  22. } ngx_pool_data_t;
  23. struct ngx_pool_s {
  24. /*内存池中内存空间*/
  25. ngx_pool_data_t d;
  26. /*最大内存限定*/
  27. size_t max;
  28. /*当前内存池分配内存位置*/
  29. ngx_pool_t *current;
  30. /*缓存chain链表, 重新申请时从这里直接取出*/
  31. ngx_chain_t *chain;
  32. /*大块内存链表, 很简单直接分配内存, 挂接到链表结束为止*/
  33. ngx_pool_large_t *large;
  34. ngx_pool_cleanup_t *cleanup;
  35. ngx_log_t *log;
  36. };

创建内存池

创建一块内存池, 首先会申请一块用户指定的大小, 即size大小, 但是size很显然最小要为sizeof(ngx_pool_t)大小, 申请内存开头放置ngx_pool_t结构体, 剩余的用作内存池内存, 提供给用户使用, 如下图示

  1. |----------------> size <--------------------|
  2. |-----------------|--------------------------|
  3. p ngx_pool_t p->d.last p->d.end
  1. ngx_pool_t *
  2. ngx_create_pool(size_t size, ngx_log_t *log)
  3. {
  4. ngx_pool_t *p;
  5. /*申请size大小内存*/
  6. p = ngx_memalign(NGX_POOL_ALIGNMENT, size, log);
  7. if (p == NULL) {
  8. return NULL;
  9. }
  10. /*用户使用内存要除去sizeof(ngx_pool_t)大小*/
  11. p->d.last = (u_char *) p + sizeof(ngx_pool_t);
  12. /*设置分配内存结束位置*/
  13. p->d.end = (u_char *) p + size;
  14. p->d.next = NULL;
  15. p->d.failed = 0;
  16. size = size - sizeof(ngx_pool_t);
  17. p->max = (size < NGX_MAX_ALLOC_FROM_POOL) ? size : NGX_MAX_ALLOC_FROM_POOL;
  18. /*设置当前使用的pool为p,因为就一个*/
  19. p->current = p;
  20. p->chain = NULL;
  21. p->large = NULL;
  22. p->cleanup = NULL;
  23. p->log = log;
  24. return p;
  25. }

申请内存

分配带内存对齐的内存, 一般用于结构体, 加快访问速度.

  1. void *
  2. ngx_palloc(ngx_pool_t *pool, size_t size)
  3. {
  4. u_char *m;
  5. ngx_pool_t *p;
  6. /*size大小决定进行小块内存分配还是大块内存分配方案*/
  7. if (size <= pool->max) {
  8. /*取出当前pool*/
  9. p = pool->current;
  10. do {
  11. m = ngx_align_ptr(p->d.last, NGX_ALIGNMENT);
  12. /*判断内存是否足够, 足够直接返回*/
  13. if ((size_t) (p->d.end - m) >= size) {
  14. p->d.last = m + size;
  15. return m;
  16. }
  17. p = p->d.next;
  18. } while (p);
  19. /*当前内存池内存不足,重新分配新内存块*/
  20. return ngx_palloc_block(pool, size);
  21. }
  22. return ngx_palloc_large(pool, size);
  23. }

分配原生大小内存, 一般字符串, 一整块内存的时候使用.

  1. void *
  2. ngx_pnalloc(ngx_pool_t *pool, size_t size)
  3. {
  4. u_char *m;
  5. ngx_pool_t *p;
  6. if (size <= pool->max) {
  7. p = pool->current;
  8. do {
  9. m = p->d.last;
  10. if ((size_t) (p->d.end - m) >= size) {
  11. p->d.last = m + size;
  12. return m;
  13. }
  14. p = p->d.next;
  15. } while (p);
  16. return ngx_palloc_block(pool, size);
  17. }
  18. return ngx_palloc_large(pool, size);
  19. }

重新分配一个pool

  1. static void *
  2. ngx_palloc_block(ngx_pool_t *pool, size_t size)
  3. {
  4. u_char *m;
  5. size_t psize;
  6. ngx_pool_t *p, *new, *current;
  7. /*内存大小和第一次用户指定的大小一致*/
  8. psize = (size_t) (pool->d.end - (u_char *) pool);
  9. m = ngx_memalign(NGX_POOL_ALIGNMENT, psize, pool->log);
  10. if (m == NULL) {
  11. return NULL;
  12. }
  13. new = (ngx_pool_t *) m;
  14. new->d.end = m + psize;
  15. new->d.next = NULL;
  16. new->d.failed = 0;
  17. /*由于只使用了ngx_pool_data_t数据结构, 因此这里实际可使用的内存只去除了sizeof(ngx_pool_data_t)大小, 跟创建时sizeof(ngx_pool_t)不同*/
  18. m += sizeof(ngx_pool_data_t);
  19. m = ngx_align_ptr(m, NGX_ALIGNMENT);
  20. new->d.last = m + size;
  21. current = pool->current;
  22. /*遍历链表最后位置, 但current并不一定到最后, current从分配失败次数少于三次位置开始, 目的是减少分配时遍历的次数*/
  23. for (p = current; p->d.next; p = p->d.next) {
  24. if (p->d.failed++ > 4) {
  25. current = p->d.next;
  26. }
  27. }
  28. /*最新分配的内存放置到链表末尾*/
  29. p->d.next = new;
  30. pool->current = current ? current : new;
  31. return m;
  32. }

关于大块内存申请是直接向系统申请, 释放的时候直接返回给系统, 没有什么好讲的.

NGINX(二)内存池的更多相关文章

  1. Nginx 之 内存池

    1.基本结构 先来学习一下nginx内存池的几个主要数据结构:[见:./src/core/ngx_palloc.h/.c]     ngx_pool_data_t(内存池数据块结构) 1: typed ...

  2. nginx 内存池分析

    最近nginx的源码刚好研究到内存池,这儿就看下nginx内存池的相关的东西. 一,为什么要使用内存池 大多数的解释不外乎提升程序的处理性能及减小内存中的碎片,对于性能优化这点主要体现在: (1)系统 ...

  3. NGINX 内存池有感

    写在前面 写NGINX系列的随笔,一来总结学到的东西,二来记录下疑惑的地方,在接下来的学习过程中去解决疑惑. 也希望同样对NGINX感兴趣的朋友能够解答我的疑惑,或者共同探讨研究. 整个NGINX系列 ...

  4. nginx源码学习----内存池

    最近在进行监控平台的设计,之前一直觉得C/C++中最棘手的部分是内存的管理上,远不止new/delete.malloc/free这么简单.随着代码量的递增,程序结构复杂度的提高.各种内存方面的问题悄然 ...

  5. nginx源码分析—内存池结构ngx_pool_t及内存管理

    Content 0. 序 1. 内存池结构 1.1 ngx_pool_t结构 1.2 其他相关结构 1.3 ngx_pool_t的逻辑结构 2. 内存池操作 2.1 创建内存池 2.2 销毁内存池 2 ...

  6. nginx源代码分析之内存池实现原理

    建议看本文档时结合nginx源代码. 1.1   什么是内存池?为什么要引入内存池? 内存池实质上是接替OS进行内存管理.应用程序申请内存时不再与OS打交道.而是从内存池中申请内存或者释放内存到内存池 ...

  7. Nginx系列三 内存池的设计

    Nginx的高性能的是用非常多细节来保证,epoll下的多路io异步通知.阶段细分化的异步事件驱动,那么在内存管理这一块也是用了非常大心血.上一篇我们讲到了slab分配器,我们能够能够看到那是对共享内 ...

  8. 菜鸟nginx源代码剖析数据结构篇(九) 内存池ngx_pool_t

    菜鸟nginx源代码剖析数据结构篇(九) 内存池ngx_pool_t Author:Echo Chen(陈斌) Email:chenb19870707@gmail.com Blog:Blog.csdn ...

  9. 菜鸟nginx源码剖析数据结构篇(九) 内存池ngx_pool_t[转]

    菜鸟nginx源码剖析数据结构篇(九) 内存池ngx_pool_t Author:Echo Chen(陈斌) Email:chenb19870707@gmail.com Blog:Blog.csdn. ...

随机推荐

  1. javascript 弹出的窗口返回值给 父窗口

    直接上代码,有些地方可以用到: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> <H ...

  2. Android开发系列之搭建开发环境

    接触Android好久了,记得09年刚在中国大陆有点苗头的时候,我就知道了google有个Android,它是智能机操作系统.后来在Android出1.5版本之后,我第一时间下载了eclipse开发工 ...

  3. Entity Framework 插入数据 解决主键非自增问题

    http://blog.csdn.net/educast/article/details/8632806 与Entity Framework相伴的日子痛并快乐着.今天和大家分享一下一个快乐,两个痛苦. ...

  4. DataGridView几个基本属性

    DataGridView 经常用到,但是很多东西都不熟悉,以至于总去上网查,这次我整理一下,全部都记下来,再用就方便了. 1.禁止用户新建行,就是去掉最后那个行标题上带星号的那个行 dataGridV ...

  5. 如何使用ERStudio 生成comment

    在ER使用中,在生成sql过程中,如何批量生成字段描述,如何批量添加Owner,请看下文: 1.ER生成字段描述 2.ER生成描述添加Owner 使用的ER版本是8.0,英文版本,在操作过程中,有些配 ...

  6. C# Activex开发、打包、签名、发布

    一.前言      最近有这样一个需求,需要在网页上面启动客户端的软件,软件之间的通信.调用,单单依靠HTML是无法实现了,因此必须借用Activex来实现.由于本人主要擅长C#,自然本文给出了用C# ...

  7. 前端资源多个产品整站一键打包&包版本管理(三)—— gulp分流

    问题: 当我们一个工作台里面有好几个项目的时候,我们要为项目的前端资源进行打包,但是,gulpfile只有一个,如果我们把所有的打包都放在同一个文件里面,首先文件会越来越大,而且不便于管理,这时,我们 ...

  8. PHP学习心得(九)——函数

    一个函数可由以下的语法来定义.任何有效的 PHP 代码都有可能出现在函数内部,甚至包括其它函数和类定义. 函数名和 PHP 中的其它标识符命名规则相同.有效的函数名以字母或下划线打头,后面跟字母,数字 ...

  9. 转最简便安装python+selenium-webdriver环境方法

    最简便安装python+selenium-webdriver环境方法 from:http://www.easonhan.info/python/2013/12/07/active-python-ins ...

  10. Logback 简单使用

    1.Logback为取代log4j而生 Logback是由log4j创始人Ceki Gülcü设计的又一个开源日志组件.logback当前分成三个模块:logback-core,logback- cl ...