解读nginx内存池的设计与实现

技术文档网 2021-06-30
nginx内存管理

内存相关的几个数据结构

  • 内存池头部结构

    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 {
      u_char               *last; //可分配内存的地址
      u_char               *end;  //内存池的边界
      ngx_pool_t           *next; //下一块内存池
      ngx_uint_t            failed;  //分配失败的次数
    } ngx_pool_data_t;
    
  • 大块内存结构

    struct ngx_pool_large_s {
      ngx_pool_large_t     *next; //指向下一个大块内存
      void                 *alloc;//指向本块的大块内存
    };
    //next是从内存池的头部连接的一个单链表指针
    //next是在内存池中分配的小内存,组成一个单链表把大块内存连接起来
    //alloc是指向大块内存的内存地址
    

pool结构

nginx内存池是以单链表的形式管理的,其中只有在链表头,也就是第一个pool中有关于ngx_pool_t字段的记录,其余节点都只有ngx_pool_data_t字段,内存池的可用内存是ngx_pool_data_t中的lastend来记录的。头结点中的ngx_pool_t字段会记录关于large页的管理链,和清理管理链cleanup

有关资源清理的设计

nginx清理cleanup这个结构设计为通用行的,每一个需要清理的资源节点都对应的有自己的clean handler,所以,可以使用这一套清理框架来设计自己的清理逻辑。


/*
*    分配一个可以用于回调函数清理内存块的内存
*/
ngx_pool_cleanup_t *
ngx_pool_cleanup_add(ngx_pool_t *p, size_t size)
{
    ngx_pool_cleanup_t  *c;
    //分配一个ngx_pool_cleanup_t
    c = ngx_palloc(p, sizeof(ngx_pool_cleanup_t));
    if (c == NULL) {
        return NULL;
    }

    if (size) {
        //分配一个data成员的内存
        c->data = ngx_palloc(p, size);
        if (c->data == NULL) {
            return NULL;
        }

    } else {
        c->data = NULL;
    }
    //handler是清理的回调函数
    c->handler = NULL;
    c->next = p->cleanup;

    p->cleanup = c;

    ngx_log_debug1(NGX_LOG_DEBUG_ALLOC, p->log, 0, "add cleanup: %p", c);

    return c;
}
ngx_pool_t中的cleanup字段管理着一个特殊的链表,该链表的每一项都记录着一个特殊的需要释放的资源。
对于这个链表中每个节点所包含的资源如何去释放,是自说明的。这也就提供了非常大的灵活性。
意味着,ngx_pool_t不仅仅可以管理内存,通过这个机制,也可以管理任何需要释放的资源

相关文章

  1. app多版本的服务端部署

    背景 手机客户端按一定周期发版,但是客户不一定会及时更新到最新版本,所以需要服务端能支持旧版手机客户端。 服务端支持旧版手机客户端的方式主要有: 相同的接口支持不同版本手机端的请求,需要服务端接口

  2. 反向代理时URI的处理

    当使用proxy_pass的时候,请求的URI传递给服务器是有一定的规则的。 proxy_pass带有URI 比如下面的配置: location /name/ { proxy_pass htt

  3. nginx-echo-命令引发的探索

    起因 最初在 nginx.conf 中调试时,当时希望 echo 出对应的变量值,并没有成功。起初认为是 nginx 安装时,并没有安装 echo 模块,然而事后发现实际用的是 openresty,o

  4. nginx499状态码产生的原因

    什么是 nginx 的 499 499 是 nginx 扩展的 4xx 错误,目的只是用于记录,并没有实际的响应。看一下 nginx 源码 ngx_http_request.h 对 499 的定义:

  5. Nginx配置文件参数说明

    定义Nginx运行的用户和用户组 user www www; nginx进程数,建议设置为等于CPU数量*核数。 worker_processes 8; 全局错误日志定义类型,[ debug |

随机推荐

  1. app多版本的服务端部署

    背景 手机客户端按一定周期发版,但是客户不一定会及时更新到最新版本,所以需要服务端能支持旧版手机客户端。 服务端支持旧版手机客户端的方式主要有: 相同的接口支持不同版本手机端的请求,需要服务端接口

  2. 反向代理时URI的处理

    当使用proxy_pass的时候,请求的URI传递给服务器是有一定的规则的。 proxy_pass带有URI 比如下面的配置: location /name/ { proxy_pass htt

  3. nginx-echo-命令引发的探索

    起因 最初在 nginx.conf 中调试时,当时希望 echo 出对应的变量值,并没有成功。起初认为是 nginx 安装时,并没有安装 echo 模块,然而事后发现实际用的是 openresty,o

  4. nginx499状态码产生的原因

    什么是 nginx 的 499 499 是 nginx 扩展的 4xx 错误,目的只是用于记录,并没有实际的响应。看一下 nginx 源码 ngx_http_request.h 对 499 的定义:

  5. Nginx配置文件参数说明

    定义Nginx运行的用户和用户组 user www www; nginx进程数,建议设置为等于CPU数量*核数。 worker_processes 8; 全局错误日志定义类型,[ debug |