core/ngx_palloc.h头文件分析
本章我们主要介绍一下ngx_palloc.h,其实现了Nginx中最基本的内存池操作。nginx中大多数的内存分配都是在pool中完成的,在pool中分配的内存在pool被销毁时会被自动的释放。这就使得可以获得很高的内存分配性能,并使得内存控制更加简单。
一个pool在内部分配对象空间时都是在一个连续的内存块(block)来进行的。一旦一个block满了之后,就会分配一个新的block并添加到pool的block list中。当所请求分配的空间过大,而不能在一个单独的块中进行分配时,则该请求会被转换到使用操作系统的allocator,然后将其返回的内存指针存放到pool中,以方便后续通过pool来释放该内存块。
Nginx里内存的使用大都十分有特色: 申请了永久保存,抑或伴随这请求的结束而全部释放,还有写满了缓冲再从头接着写,这么做的原因也主要取决于Web Server的特殊的场景,内存的分配和请求相关,一条请求处理完毕,即可释放其相关的内存池,降低了开发中对内存资源管理的复杂度,也减少了内存碎片的存在。
1. 相关宏的定义
这里定义了一些宏:
-
NGX_MAX_ALLOC_FROM_POOL: 用于定义内存池中数据块的最大值。一般在x86机器上为(4096-1)
-
NGX_DEFAULT_POOL_SIZE: 一个pool默认的总空间大小(注意这里包括
ngx_pool_t
结构体本身的大小) -
NGX_POOL_ALIGNMENT: 内存池本身分配在以16字节对齐的空间上
-
NGX_MIN_POOL_SIZE: 内存池的最小空间大小。这里
ngx_pool_t
的大小为80,而ngx_pool_large_t
的大小为16,因此算出内存池的最小空间大小为112字节。
2. ngx_pool_cleanup_t数据结构
本数据结构主要用于指示如何释放内存池资源:
-
handler: 释放内存池资源的回调函数
-
data: 指向要清除的数据
-
next: 指向下一个ngx_pool_cleanup_t结构。
3. ngx_pool_large_t数据结构
大内存块结构。当待分配空间已经超过了池子自身大小,nginx也没有别的好办法,只好按照你需要分配的大小,实际去调用malloc()函数去分配。例如池子大小是1K,而待分配大小是1M。实际上池子里只存储了ngx_pool_large_t结构,这个结构的alloc指针,指向被分配的内存,并把这个指针返回给系统使用。
-
next: 指向下一块大内存
-
alloc: 指向分配的大块内存
4. ngx_pool_t数据结构
下面我们简要介绍一下这两个数据结构:
1) ngx_pool_data_t结构体
ngx_pool_data_t
用于表示内存池中的一个数据块,供用户分配之用。下面介绍一下各个字段的含义:
-
last: 当前内存分配结束位置,即下一段可分配内存的起始位置;
-
end: 本内存块的结束位置;
-
next: 内存池里面有很多块内存,这些内存块就是通过该指针连成链表的
-
failed: 统计该内存池不能满足分配请求的次数,即分配失败的次数;
2) ngx_pool_t结构体
ngx_pool_t
用于维护整个内存池的头部信息。下面介绍一下各个字段的含义:
-
d: 内存池的数据块
-
max: 数据块大小,可分配小块内存的最大值
-
current: 当前内存池,以后的内存分配从该指针指向的内存池中分配;
-
chain: 指向一个ngx_chain_t结构
-
large: 指向大块内存分配,nginx中,大块内存分配直接采用标准系统接口malloc
-
cleanup: 析构函数
-
log: 内存分配相关的日志记录
下面画出ngx_pool_t
结构的示意图:
注: 其实上面图画的有些小问题,对于pool->d.next
指向的ngx_pool_t
结构,在实际使用过程中其实指向的是一个ngx_pool_data_t
结构,即只是ngx_pool_t结构的一小部分。这样做的原因主要是为了节省空间。
5. ngx_pool_cleanup_file_t结构
此结构主要用于针对Nginx静态文件缓存
(open file cache)的pool在释放时传递相应的上下文。
-
fd: 所打开文件的句柄
-
name: 文件的名称
-
log: 所关联的日志对象
6. 相关函数声明
[参看]