NGINX内存池的设计

服务器
NGINX常被用来作为HTTP和反向代理Web服务器, NGINX用很少的代码量,达到了很好的实际效果,值得学习借鉴。

NGINX是高性能高并发服务器的典范,NGINX常被用来作为HTTP和反向代理Web服务器,作为HTTP服务器,NGINX的工作模式是:接收一个来自client的request,处理该request,然后向client吐出response。

这样的工作模式非常适合用内存池优化动态内存分配,NGINX内存池也是其优秀设计的典型案例。

NGINX为每个连接创建一个内存池对象,在处理该连接请求的过程中,所有的动态内存分配请求,都向内存池提交,返回结果后,再清理该连接的内存池,清理内存池不会把内存真正返回系统,会根据策略把一定量的内存缓存起来复用。

因为请求的处理过程都在一个线程内进行,所以该连接的内存池不需要处理多线程同步(免锁),中途也不需要释放内存(返回结果后统一释放),避免了内存泄漏的隐患,安全性也得到了提升。

NGINX内存池的设计概要

  • request处理过程中,所有动态内存分配,都向连接专属的内存池申请。
  • 大尺寸内存按需分配,走malloc/free或mmap/munmap,大块内存块用链表串起来。
  • 小尺寸内存从内存页分配,批发转零售:先通过malloc/mmap申请一个4K(大小可配)的内存页(批发),再从内存页里细分(零售),内存也也会用链表串起来。
  • 内存池记着当前页指针,下次分配先从当前页尝试,内存页多次不满足分配请求后,才会修改当前页指针。

图片

NGINX内存池的设计考虑 

对动态内存分配请求,根据参数size,区别对待:

(1) 如果大于等于某个阈值,则被视为大块内存,大块内存分配直接调用标准C的malloc函数或系统调用mmap,内存池为大块内存维护一个单独的链表,用于统一释放,大块也支持单独释放。

(2) 如果小于某个阈值,会先判断当前页剩余的内存大小能否满足本次分配的尺寸要求:

  • 如果满足,则简单的移动游标(实际上会考虑对齐要求),并返回移动前的游标位置(地址),这种情况概率高、效率高
  • 如果不满足,再次通过底层接口分一内存页,并从该页划分一块满足本次分配请求,新分配的内存页,会通过链表串起来。

关于当前页指针:

  • 假设当前页还剩500字节,但接下来的分配请求512字节,因为剩余尺寸不够,那么内存池会分配一个4K的新内存页,从新内存页划分出512字节返回,并把新内存页串到内存页链表。
  • 当前页指针还是指向剩余500字节的内存页,内存池下次分配请求依然从旧内存页开始尝试。
  • 只有一个内存页在多次不满足分配尺寸要求后,才会修改内存池的当前页指针,这样做是为了减少内存浪费。因为如果多次尝试后,依然不满足,那么这个内存页的剩余空间大概率会比较小,这时候跳过它,也就合情合理了。
  • 大多数的分配是请求小块内存,这部分高频请求用简单的移动游标满足,性能非常高,因为分配出去的小块内存不支持中途释放,所以它消除了通用内存分配器为每个内存块增加的头部/尾部,提高了有效载荷,内存利用率高。
  • 大块内存的分配是小概率事件,因为大块被单独的链表串起来,所以既支持统一释放,也可以通过遍历链表的方式中途释放大内存块,因为大块数量不多,所以遍历不会很耗费。之所以要支持大块内存的中途释放,是为了避免内存占用过度膨胀(大块内存的一块就可能很大),提高内存复用。

NGINX内存池小结

  • 为每个连接配一个内存池,使得无锁成为可能。
  • NGINX内存池专注于做好小块内存的分配,大块的分配只是简单转交给malloc/mmap,它在处理当前内存页指针的细节上做的比较好,提升了内存利用率。
  • 跟一般内存池一样,NGINX内存池通过牺牲小块内存的中途释放能力,换取通过移动游标分配内存的高性能和高内存利用率;通过缓存内存的提升复用,本质上是以空间换时间,这些都体现了TradeOff的思想。
  • NGINX用很少的代码量,达到了很好的实际效果,值得学习借鉴。
责任编辑:赵宁宁 来源: 码砖杂役
相关推荐

2011-08-16 09:34:34

Nginx

2022-03-29 15:10:22

架构设计模型

2018-02-07 16:23:58

连接池内存池AI

2020-10-19 10:01:12

Nodejs线程池设计

2024-05-06 11:19:20

内存池计算机编程

2013-11-07 09:42:42

对象对象池加速

2020-06-04 12:15:37

Go内存池对象池

2021-03-02 08:34:35

分布式管理设计

2023-10-07 15:56:49

三链表缓存页flush链表

2021-06-08 09:49:01

协程池Golang设计

2024-11-06 09:39:52

2019-03-18 09:50:44

Nginx架构服务器

2013-08-07 10:24:24

JDBC链接池

2021-10-17 21:04:34

AI内存池集群

2021-11-29 09:38:12

设计模式对象池模式Object Pool

2020-10-20 17:03:19

戴尔

2018-08-15 10:29:58

NettyJDK内存

2021-09-17 11:08:05

内存

2024-02-26 00:00:00

Nginx服务器HTTP

2013-11-29 10:24:52

Cluster设计资源池
点赞
收藏

51CTO技术栈公众号