Nginx 中的内存池
Posted 天空的代码世界
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Nginx 中的内存池相关的知识,希望对你有一定的参考价值。
nginx 自己把所用的数据结构轮子都自己造了一遍,我们来看看内存池吧。
一、背景
之前在内部分享了一次 Nginx,并写了一篇文章《》。
现在继续来看看 Nginx 里面有意思的代码吧。
第一个轮子就是:内存池。
二、内存池
Nginx 实现了一个简单的内存池,效率非常高,但是可用性非常差。
内存池,顾名思义,就是预先从操作系统里申请好内存,程序实际需要内存的时候,直接在用户态分配即可。
为啥要这样做呢?
因为默认分配内存涉及到与操作系统打交道,比较慢(还可能有内存碎片什么的)。
而自己管理内存则只需要第一次和操作系统打交道,之后都是在自己的数据上操作的,无非一些变量的加加减减,性能非常高。
void * ngx_palloc_s(ngx_pool_t* pool, size_t size){
char* m = pool->d.last;
p->d.last = m + size;
return m;
}
看了上面的代码,很多独立思考的人会有很多疑问。
1.比如内存不够了怎么办?
2.内存需要对齐怎么办?
3.内存怎么回收?
这三个问题也很容易回答。
三、内存不够了怎么办?
不够了创建新的内存池即可。
也就是内存池是一个链表,这样就不存在不够的问题了。
创建新内存池的代码也很简单。
调用系统的申请内存函数,然后把新内存池挂在链表的最后面。
这里面有一个优化,由于链表要在最后插入一个元素的时候,需要遍历链表。
nginx就在每个内存池上加了一个计数器,如果一个内存池被遍历四次,就把当前内存池设置为current。
这样就可以保证内存池有效链表节点的个数不会超过7个。
四、内存需要对齐怎么办?
那就先对齐内存,在分配空间。
void * ngx_palloc_s(ngx_pool_t* pool, size_t size){
char* m = pool->d.last;
m = ngx_align(m);
p->d.last = m + size;
return m;
}
可能有人会问:为什么要对齐内存?
这个涉及到的学问就有意思了。
第三是很多CPU只支持字节对齐的程序。
这个就比较霸道了,硬件不支持不对齐的程序,那我们只好对齐了。
五、内存怎么回收?
这个是最魔幻的地方。
答案是业务自己回收,这里不提供回收函数。
吐血。。。
那随便找个使用内存池的代码,看看怎么回收的吧。
以array
数据结构轮子为例。
代码中可以看到,回收的时候有个判断。
回收的数据必须是内存池最后一个分配的内存才可以回收。
这个就要求业务自己严格保证申请内存的顺序和回收内存的顺序完全相反了。
一丁点都不能乱,乱一个就全部不能回收了。
另外,再考虑我们分配内存的时候曾有过内存对齐操作。
如果分配内存时进行了内存对齐,将永远也满足不了这个回收条件了,也就是永远也回收不了了。
六、最后
看到这里, Nginx 的内存池就看完了(大内存逻辑就不提了)。
是不是实现的特别简单、性能特别高。
但是也应了我上篇文章《》说的那句话:
而 Nginx 为了提高性能,所有的功能都自己来实现了。
比如 SLAB 内存管理,array、list、hash、红黑树、regex等等。
自己实现的时候,仅仅实现自己需要的功能。
这样做出来的功能没有那么通用,但是也没有冗余,自己使用时性能会更高。
最后了,插播一个福利。
今天摔键盘的时候,摔出一本书来,于是我想:这些书不能浪费了。
既然我不看,可以分享给大家看。
我是谁:
我是天空,这里有算法、技术、理财、读书、电影、以及一个程序员的生活。
我是观点:
如果你认为这篇文章对你有启发,可以进行一次有深度的思考并留言,时间久了,你会发现自己是一个会独立思考的人。
最近文章:
❖都是对笔者的一种支持 ❖
以上是关于Nginx 中的内存池的主要内容,如果未能解决你的问题,请参考以下文章
菜鸟nginx源代码剖析数据结构篇 内存池ngx_pool_t
14.VisualVM使用详解15.VisualVM堆查看器使用的内存不足19.class文件--文件结构--魔数20.文件结构--常量池21.文件结构访问标志(2个字节)22.类加载机制概(代码片段