概述
Nginx 使用内存池对内存进行管理,内存管理的实现类似于前面文章介绍的《STL源码剖析——空间配置器》,把内存分配归结为大内存分配 和小内存分配。若申请的内存大小比同页的内存池最大值 max 还大,则是大内存分配,否则为小内存分配。
- 大块内存的分配请求不会直接在内存池上分配内存来满足请求,而是直接向系统申请一块内存(就像直接使用 malloc 分配内存一样),然后将这块内存挂到内存池头部的 large 字段下。
- 小块内存分配,则是从已有的内存池数据区中分配出一部分内存。
Nginx 内存管理相关文件:
- src/os/unix/ngx_alloc.h/.c
- 内存相关的操作,封装了最基本的内存分配函数。
- 如 free / malloc / memalign / posix_memalign,分别被封装为 ngx_free,ngx_alloc / ngx_calloc, ngx_memalign
- ngx_alloc:封装malloc分配内存
- ngx_calloc:封装malloc分配内存,并初始化空间内容为0
- ngx_memalign:返回基于一个指定 alignment 的大小为 size 的内存空间,且其地址为 alignment 的整数倍,alignment 为2的幂。
- src/core/ngx_palloc.h/.c
- 封装创建/销毁内存池,从内存池分配空间等函数。
Nginx 内存分配总流图如下:
其中 size 是用户请求分配内存的大小,pool是现有内存池。
内存池基本结构
Nginx 内存池基本结构定义如下:
/* 内存池结构 */
/* 文件 core/ngx_palloc.h */
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_chain_t 结构 */
ngx_pool_large_t *large;/* 大块内存链表,即分配空间超过 max 的内存 */
ngx_pool_cleanup_t *cleanup;/* 析构函数,释放内存池 */
ngx_log_t *log;/* 内存分配相关的日志信息 */
};
/* 文件 core/ngx_core.h */
typedef struct ngx_pool_s ngx_pool_t;
typedef struct ngx_chain_s ngx_chain_t;
大块内存分配的数据结构如下:
typedef struct ngx_pool_large_s ngx_pool_large_t;
struct ngx_pool_large_s{
ngx_pool_large_t *next; //指向下一块大块内存
void *alloc; //指向分配的大块内存
};
其他数据结构如下:
typedef void (*ngx_pool_cleanup_pt)(void *data); //cleanup的callback类型
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; //下一个cleanup callback
};
typedef struct {
ngx_fd_t fd;
u_char *name;
ngx_log_t *log;
} ngx_pool_cleanup_file_t;
内存池基本机构之间的关系如下图所示:
ngx_pool_t 的逻辑结构
上面数据结构之间逻辑结构图如下: 该图是采用 UML 画的,第一行黑色粗体表示对应数据结构,第二行是结构内的成员,冒号左边是变量,冒号右边是变量的类型;
上面数据结构之间逻辑结构图如下: 该图是采用 UML 画的,第一行黑色粗体表示对应数据结构,第二行是结构内的成员,冒号左边是变量,冒号右边是变量的类型;