浅谈nginx内存池(一)
一直听别人说nginx的内存池设计非常巧妙,所以就去学习了一下。感觉确实很不错。在这里我就说说我的理解吧。可能有的地方理解不到位,请多谅解!
1.首先介绍一下内存池的结构:
//内存池的结构
struct ngx_pool_t {
//数据区的指针
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;
};
而当内存池初始化的时候,ngx_pool_t相当于内存池的一个头,保存了当前内存池的一些必要信息而已。
当内存池存取数据的时候,有两种情况:
(1)小块数据。他是直接从内存池中取得数据的。
(2)大块数据。他是直接malloc一块数据,也就是说是从内存池外部分配数据的,然后将这个指针保存到内存中。
问题:如何判断是小块数据还是大块数据?
答:如果需要分配的内存大于max(在前面的ngx_pool_t中),则认为是较大内存,否则是较小内存。
2.下面介绍一下数据区的指针ngx_pool_data_t
这个结构其实相对来说还是比较简单的,它包含了我们所需要操作这块内存池数据的一些指针。结构体如下:
typedef struct {
//表示已使用数据的结尾
u_char *last;
//表示当前内存池的结尾
u_char *end;
//指向下一块内存池
ngx_pool_t *next;
///失败标记
ngx_uint_t failed;
} ngx_pool_data_t;
由此可以知道:end - last表示内存池中还未使用的内存大小。
failed域主要是标记我们请求的时候由于内存池空间不够,我们需要分配一个子内存池的次数。
问题:在nginx中如果内存池满了该如何处理?
答:这个就是比较特殊的地方了。一般来说,当我们一个内存池请求一块内存时,如果此时内存池已经满了,那么就是扩大内存池。但是nginx中却不是这样做的。他是直接再分配一个内存池,然后链接到ngx_pool_data_t中的next指针上。也就是说,在nginx中,每一个内存池都会包含一些子内存池,我们请求内存的时候都需要遍历这些子内存池。
3.ngx_chain_t这个比较复杂,我们放到后面介绍,下来我们看看ngx_pool_large_s,他表示了大块的内存,这个结构也是很简单的,结构如下:
struct ngx_pool_large_s {
//指向下一块large
ngx_pool_large_t *next;
//指向数据
void *alloc;
};
4.ngx_pool_cleanup_s
这个结构是用来表示内存池中的数据的清理handler,结构如下:
struct ngx_pool_cleanup_s {
//清理函数
ngx_pool_cleanup_pt handler;
//传递给清理函数的数据
void *data;
//表示下一个清理handler
ngx_pool_cleanup_t *next;
};
具体结构如图所示:
下一节就要进入具体的函数啦!!!