小知识:详解Nginx中基本的内存池初始化配置

ngx_cycle初始化 整个初始化过程中,最重要的就是全局变量 nginx_cycle 的初始化,很多变量都是在这个过程中初始化的

nginx_cycle 又是通过两个局部变量 init_cycle 和 cycle 实现初始化的

事实上,日志初始化也可以算是对 nginx_cyle 的初始化,因为在代码中接下来马上要发生的就是一个赋值

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
ngx_memzero(&init_cycle, sizeof(ngx_cycle_t));
init_cycle.log = log;
ngx_cycle = &init_cycle;
// 创建内存池 1KB
init_cycle.pool = ngx_create_pool(1024, log);
if (init_cycle.pool == NULL) {
return 1;
}
// 保存调用参数到全局变量,init_cycle 只用于提供 log 参数
if (ngx_save_argv(&init_cycle, argc, argv) != NGX_OK) {
return 1;
}
// 保存配置文件路径、程序运行路径、调用参数到 init_cycle
if (ngx_process_options(&init_cycle) != NGX_OK) {
return 1;
}
// 获取操作系统信息、CPU信息、最大连接数、是否支持非阻塞连接等
if (ngx_os_init(log) != NGX_OK) {
return 1;
}
/*
* ngx_crc32_table_init() requires ngx_cacheline_size set in ngx_os_init()
*/
// 对齐校验表
if (ngx_crc32_table_init() != NGX_OK) {
return 1;
}
// 获取所有继承连接fd的相关信息
if (ngx_add_inherited_sockets(&init_cycle) != NGX_OK) {
return 1;
}

内存池 nginx 是通过资源集中管理的方式管理资源的,即打开所有即将要用的资源,以备随时取用,无论是文件还是内存

这样做的好处是避免了每次创建、打开资源造成的性能消耗

因此,便有了内存池模块,用来集中申请内存资源并进行内存资源的管理和分配

内存池结构:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// struct ngx_pool_data_t
// 内存池数据块结构 {{{
typedef struct {
u_char    *last;  // 当前内存分配的结束位置
u_char    *end;  // 内存池的结束位置
ngx_pool_t   *next;  // 下一内存池
ngx_uint_t   failed; // 内存分配失败计数
} ngx_pool_data_t; // }}}
// struct ngx_pool_s
// 内存池结构 {{{
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;  // 内存分配相关的log
}; // }}}

在这个函数中,使用了一个封装好的函数 ngx_memalign,这个函数是对系统中按照数据对齐方式分配内存的函数的封装,在不同的系统中实现方式不同,通过宏定义,实现了操作系统的适配,这是一个很漂亮的技巧

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#if (NGX_HAVE_POSIX_MEMALIGN)
// void * ngx_memalign(size_t alignment, size_t size, ngx_log_t *log)
// 用数据对齐的方式进行内存分配 {{{
void *
ngx_memalign(size_t alignment, size_t size, ngx_log_t *log)
{
void *p;
int err;
// size 单位是 byte 而不是 bit
err = posix_memalign(&p, alignment, size);
if (err) {
ngx_log_error(NGX_LOG_EMERG, log, err,
“posix_memalign(%uz, %uz) failed”, alignment, size);
p = NULL;
}
ngx_log_debug3(NGX_LOG_DEBUG_ALLOC, log, 0,
“posix_memalign: %p:%uz @%uz”, p, size, alignment);
return p;
} // }}}
#elif (NGX_HAVE_MEMALIGN)
// void * ngx_memalign(size_t alignment, size_t size, ngx_log_t *log)
// 用数据对齐的方式进行内存分配 {{{
void *
ngx_memalign(size_t alignment, size_t size, ngx_log_t *log)

所有有关内存分配的系统调用函数的封装都定义在 ngx_alloc.c 文件中

这里用到了 posix_memalign 系统调用,使用这个系统调用分配出来的内存是默认按照第二个参数的大小对齐的,这样在进行数据读写的时候,CPU可以周期地对整块数据进行读写,很大程度的节省了CPU时间

这个系统调用所分配的内存也是存在于堆内存中的,可以使用 free 函数进行释放,不过 malloc 分配的内存默认也是对齐的,它相对于 malloc 的优势仅仅在于可以指定默认对齐大小。

函数完成了内存池的初步分配,执行后 pool 取值:
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
$23 = (ngx_pool_t *) 0x80fe9f0
(gdb) p *init_cycle.pool
$24 = {
d = {
last = 0x80fea18,
end = 0x80fedf0,
next = 0x0,
failed = 0
},
max = 984,
current = 0x80fe9f0,
chain = 0x0,
large = 0x0,
cleanup = 0x0,
log = 0x80e3020 <ngx_log>
}

如下图所示:

%小知识:详解Nginx中基本的内存池初始化配置-猿站网-插图

声明: 猿站网有关资源均来自网络搜集与网友提供,任何涉及商业盈利目的的均不得使用,否则产生的一切后果将由您自己承担! 本平台资源仅供个人学习交流、测试使用 所有内容请在下载后24小时内删除,制止非法恶意传播,不对任何下载或转载者造成的危害负任何法律责任!也请大家支持、购置正版! 。本站一律禁止以任何方式发布或转载任何违法的相关信息访客发现请向站长举报,会员发帖仅代表会员个人观点,并不代表本站赞同其观点和对其真实性负责。本网站的资源部分来源于网络,如有侵权烦请发送邮件至:2697268773@qq.com进行处理。
建站知识

小知识:简单操作系统 FreeDOS 如何启动

2023-4-29 4:35:04

建站知识

小知识:浅淡Linux的IO和磁盘IO的检测

2023-4-29 4:43:33

0 条回复 A文章作者 M管理员
    暂无讨论,说说你的看法吧
个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索