网站首页 > 技术教程 正文
今天我们一起来看一下Nginx的内存池。那么Nginx为什么会使用内存池呢?这是为了减少内存碎片的产生,Nginx提前帮我们申请好了一块大的内存,这样我们在申请小块内存的时候,就会在已经创建的内存池里去分配就好了。内存管理分为段式管理和页式管理。关于内存管理这块我们后面有机会再深入介绍。
在我们的应用程序里的内存大概可以分为栈内存,堆内存。
我等码农在使用堆内存的步骤大致可以分3步:
- 申请内存
- 使用内存
- 释放内存
这里穿插一个小知识点:C语言里的malloc 和 free 函数不是系统调用,而是 C 语言的运行时间。也就是说malloc的时候并不会进行用户态到内核态到切换。
介绍:
Nginx 将内存池里的内存分为两类:小块内存,大块内存。
对于小块内存,它在申请后并不需要释放,而是等到释放内存池时再释放。
对于大块内存,可以调用相关接口进行释放,也可以等内存池释放后再释放。这是因为Nginx的内存池支持增加回调函数,当内存池被释放的时候,会调用回调函数用来释放用户申请的资源。这里值得一提的是,回调函数还可以有多个,是通过链表的形式来链接的,遍历链表一一回调。
下面我们一起看一下内存池的操作方法。
函数原型如下:
ngx_pool_t *ngx_create_pool(size_t size, ngx_log_t *log);
void ngx_destroy_pool(ngx_pool_t *pool);
void ngx_reset_pool(ngx_pool_t *pool);
void *ngx_palloc(ngx_pool_t *pool, size_t size);
void *ngx_pnalloc(ngx_pool_t *pool, size_t size);
void *ngx_pcalloc(ngx_pool_t *pool, size_t size);
void *ngx_pmemalign(ngx_pool_t *pool, size_t size, size_t alignment);
ngx_int_t ngx_pfree(ngx_pool_t *pool, void *p);
ngx_pool_cleanup_t *ngx_pool_cleanup_add(ngx_pool_t *p, size_t size);
void ngx_pool_run_cleanup_file(ngx_pool_t *p, ngx_fd_t fd);
void ngx_pool_cleanup_file(void *data);
void ngx_pool_delete_file(void *data);
从表格中,我们可以看到Nginx其实已经提供封装了malloc、free的ngx_alloc、ngx_free方法,那为什么还要再整一个挺复杂的内存池呢?这里对于没有垃圾回收机制的C语言编写的应用来说,最容易犯的错就是内存泄露。(我当年写C程序的时候就经常段错误)。当分配内存与释放内存的逻辑相距遥远时,还很容易发生同一块内存被释放两次。内存池就是为了降低程序员犯错几率的:模块开发者只需要关心内存的分配,而释放则交由内存池来负责。是不是想起了php-fpm?一次请求中phper们一顿操作猛如虎,请求结束php-fpm都给你释放了。所以,phper对内存都不太care的只要不oom就可以了。
Nginx的内存池分为两种:
如果是一个HTTP请求,则在请求的内存池上分配内存。请求内存池是在一个请求结束后,被销毁的。
如果是一个连接,则在连接的内存池上分配内存。Nginx主要处理Http请求,当我们有一个tcp链接的时候,这个链接如果是Keepalive链接,那这上面就可能会有很多http请求。链接内存池是在链接关闭的时候才释放的。
https://nginx.org/en/docs/http/ngx_http_core_module.html#connection_pool_size
我们在官方文档可以看到
连接池的大小默认为256 或者 512个字节。
https://nginx.org/en/docs/http/ngx_http_core_module.html#request_pool_size
我们可以看到请求池的大小默认是4K,为什么会比连接池大那么多呢?
这是因为请求相对于连接而言需要保存的上下文信息要多一些,比如url,header需要保存下来。
接下来我们来看一下内存池的相关数据结构:
// 小块内存池。当分配小块内存时,剩余的预分配空间不足时,
// 会再分配1个 ngx_pool_s, 这些ngx_pool_s会通过d中的next 构成单链表。
struct ngx_pool_s {
ngx_pool_data_t d; // 内存池数据
size_t max; // 判断申请内存是大块内存 还是小块内存的标准
ngx_pool_t *current; // 多个小块内存池 构成链表,current指向分配内存时遍历的第一个小块内存池
ngx_chain_t *chain; // 用于ngx_output_chain 与内存池关系不大
ngx_pool_large_t *large; // 大块内存 组成的单链表。为了在销毁内存池时可以同时释放。
ngx_pool_cleanup_t *cleanup; // 所有需要清理的资源挂在这个单链表上 如:需要关闭/删除的文件
ngx_log_t *log; //内存池执行中 输出日志的对象
};
typedef struct ngx_pool_large_s ngx_pool_large_t;
struct ngx_pool_large_s {
ngx_pool_large_t *next; // 大块内存链表指针
void *alloc; // 指向ngx_alloc分配出的大块内存
};
猜你喜欢
- 2024-10-15 Linux下配置keepalive心跳检测部署
- 2024-10-15 性能 - 性能调优的常见手段(性能改善)
- 2024-10-15 HTTP keep-alive和TCP keepalive的区别,你了解吗?
- 2024-10-15 负载均衡:算法/策略+ LVS+Keepalive+Nginx反向代理+HAProxy
- 2024-10-15 关于Keepalive的那些事(关于keep 的短语)
- 2024-10-15 好程序员分享http的keep-alive和tcp的keep-alive区别
- 2024-10-15 TCP/IP协议栈之数据包如何穿越各层协议(绝对干货)
- 2024-10-15 HTTP持久连接-Keep-Alive(共享打印机怎么连接)
- 2024-10-15 Nginx的复用连接的功能之KeepAlive
- 2024-10-15 nginx之keepalive详解及配置(nginx配置keepalive_timeout)
你 发表评论:
欢迎- 最近发表
-
- 阿里P8大佬总结的Nacos入门笔记,从安装到进阶小白也能轻松学会
- Linux环境下,Jmeter压力测试的搭建及报错解决方法
- Java 在Word中合并单元格时删除重复值
- 解压缩软件哪个好用?4款大多数人常用的软件~
- Hadoop高可用集群搭建及API调用(hadoop3高可用)
- lombok注解@Data没有toString和getter、setter问题
- Apache Felix介绍(apache fineract)
- Spring Boot官方推荐的Docker镜像编译方式-分层jar包
- Gradle 使用手册(gradle详细教程)
- 字节二面:为什么SpringBoot的 jar可以直接运行?
- 标签列表
-
- 下划线是什么 (87)
- 精美网站 (58)
- qq登录界面 (90)
- nginx 命令 (82)
- nginx .http (73)
- nginx lua (70)
- nginx 重定向 (68)
- Nginx超时 (65)
- nginx 监控 (57)
- odbc (59)
- rar密码破解工具 (62)
- annotation (71)
- 红黑树 (57)
- 智力题 (62)
- php空间申请 (61)
- 按键精灵 注册码 (69)
- 软件测试报告 (59)
- ntcreatefile (64)
- 闪动文字 (56)
- guid (66)
- abap (63)
- mpeg 2 (65)
- column (63)
- dreamweaver教程 (57)
- excel行列转换 (56)
本文暂时没有评论,来添加一个吧(●'◡'●)