Ubuntu 下 nginx-1.24.0 源码分析 - ngx_list_t
ngx_list_t
定义在 src/core/ngx_list.h
typedef struct {
ngx_list_part_t *last;
ngx_list_part_t part;
size_t size;
ngx_uint_t nalloc;
ngx_pool_t *pool;
} ngx_list_t;
ngx_list_t
是 Nginx 中用于管理动态数组链表的核心数据结构,结合了数组的高效访问和链表的动态扩展特性。以下是对该结构体及其成员的详细解释:
成员详解
1. ngx_list_part_t *last
- 作用:指向链表的最后一个节点(
ngx_list_part_t
类型)。 - 意义:
- 用于快速定位链表的末尾,方便在链表尾部追加新元素。
- 当需要添加元素时,直接检查
last
指向的节点是否还有剩余空间。如果已满,则分配新节点并更新last
。
2. ngx_list_part_t part
- 作用:链表的首个节点(头节点)。
- 意义:
- 作为链表的起始点,遍历链表时从
part
开始。 - 结构体直接内嵌第一个节点,减少一次内存分配(避免单独为头节点分配内存)。
- 作为链表的起始点,遍历链表时从
3. size_t size
- 作用:链表中每个元素的大小(以字节为单位)。
- 意义:
- 确保每个节点分配的内存块能容纳固定大小的元素(例如存储 HTTP 头字段时,每个元素是
ngx_table_elt_t
类型)。 - 在初始化链表时指定,后续所有元素必须严格匹配该大小。
- 确保每个节点分配的内存块能容纳固定大小的元素(例如存储 HTTP 头字段时,每个元素是
4. ngx_uint_t nalloc
- 作用:每个节点预分配的元素个数。
- 意义:
- 决定每个节点的容量(
nalloc * size
字节),平衡内存占用和分配频率。 - 较大的
nalloc
减少内存分配次数,但可能浪费内存;较小的nalloc
节省内存,但增加分配开销。 - 在初始化链表时指定,通常根据实际场景调整(如 Nginx 默认使用
20
)。
- 决定每个节点的容量(
5. ngx_pool_t *pool
- 作用:指向内存池(
ngx_pool_t
类型)。 - 意义:
- 所有内存分配(节点、元素)均通过内存池完成,避免频繁调用
malloc/free
,提升性能。 - 内存池的生命周期管理链表的内存,链表销毁时由内存池统一回收,防止内存泄漏。
- 所有内存分配(节点、元素)均通过内存池完成,避免频繁调用
链表节点结构 ngx_list_part_t
每个节点(ngx_list_part_t
)的定义如下:
typedef struct ngx_list_part_s ngx_list_part_t;
struct ngx_list_part_s {
void *elts; // 指向元素数组的指针
ngx_uint_t nelts; // 当前节点中已使用的元素个数
ngx_list_part_t *next; // 指向下一个节点的指针
};
elts
:指向实际存储元素的内存块,大小为nalloc * size
。nelts
:当前节点中已存储的元素数量,初始为0
,随元素添加递增。next
:指向下一个节点,形成链表结构。
工作原理
-
初始化:
- 通过
ngx_list_init()
初始化链表,指定size
、nalloc
和pool
。 - 头节点
part
被初始化,last
指向part
。
- 通过
-
添加元素:
- 检查
last
节点的nelts
是否小于nalloc
。若有空间,直接追加元素到elts
。 - 若无空间,分配新节点(通过
pool
),更新last->next
指向新节点,并将last
移动到新节点。
- 检查
-
遍历元素:
- 从
part
开始,遍历每个节点的elts
数组,直到所有节点处理完毕。
- 从