网站首页 > 精选教程 正文
今天我们一起来看一下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-24 高性能服务器为什么需要内存池? 服务器为什么要大内存
- 2024-10-24 malloc底层原理剖析——ptmalloc内存池
- 2024-10-24 编程硬核技术:高性能低延迟内存池实现技术
- 2024-10-24 C++ linux服务器架构师学习路线(腾讯T9认证)
- 2024-10-24 C语言级联内存池之轻松零拷贝IPC c语言怎么申请内存
- 2024-10-24 Nginx自定义数据结构之字符串(String)数组(Array)链表(List)
- 2024-10-24 malloc函数背后的实现原理——内存池
- 2024-10-24 ringbuffer 消息队列 内存池 性能优化利器
- 2024-10-24 Netty内存池之PoolThreadCache详解
- 2024-10-24 C++/Linux后台开发风口:冲刺年薪50w,就学这些技术
你 发表评论:
欢迎- 最近发表
- 标签列表
-
- nginx反向代理 (57)
- nginx日志 (56)
- nginx限制ip访问 (62)
- mac安装nginx (55)
- java和mysql (59)
- java中final (62)
- win10安装java (72)
- java启动参数 (64)
- java链表反转 (64)
- 字符串反转java (72)
- java逻辑运算符 (59)
- java 请求url (65)
- java信号量 (57)
- java定义枚举 (59)
- java字符串压缩 (56)
- java中的反射 (59)
- java 三维数组 (55)
- java插入排序 (68)
- java线程的状态 (62)
- java异步调用 (55)
- java中的异常处理 (62)
- java锁机制 (54)
- java静态内部类 (55)
- java怎么添加图片 (60)
- java 权限框架 (55)
本文暂时没有评论,来添加一个吧(●'◡'●)