38

Nginx源码阅读笔记-内存池的设计

 5 years ago
source link: https://www.codedump.info/post/20190214-nginx-memory-pool/?amp%3Butm_medium=referral
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

nginx的内存池设计的比较简单了,一个内存池中分为两个部分:

  • 超过max大小的内存分配,走大块内存分配,这部分内存管理由ngx_pool_large_t结构体负责。
  • 否则就是在ngx_pool_t遍历符合要求的ngx_pool_t结构体,找到符合要求大小的pool直接返回,否则就申请一块新的内存pool。

nginx中所有请求都单独对应一个内存池,在这个请求的过程中,所有涉及到内存分配的地方,都到该请求相关的内存池中处理,而中间不会去释放回收内存,内存池的生命周期与请求一样,请求完毕则直接回收内存。这样的好处在于:统一分配和统一释放,降低了内存泄露问题的出现。

ngx_pool_data_t

先来看结构体ngx_pool_data_t,它存储每个ngx_pool_t结构体的meta元数据:

  • u_char *last:指向分配空间的可用空间。
  • u_char *end:指向分配空间的最后位置。
  • ngx_pool_t *next:指向下一个ngx_pool_t指针。
  • ngx_uint_t failed:存储本ngx_pool_t结构体分配失败次数。

67vURbV.png!web

failed成员的引入是为了避免某个pool虽然还有可用的空间,但是由于空间很小了所以经常性的分配空间失败,当累计失败的次数达到某个阈值时,下一次再次查找内存就直接跳过这个pool,而去寻找内存池链表中的下一个pool。

ngx_pool_large_t

ngx_pool_large_t结构体用于保存大内存块,这一块就比较简单粗暴了,直接分配一块大内存来使用。另外,多个大内存块之间也是以链表形式来组织数据。

// 管理超大空间的结构体
struct ngx_pool_large_s {
  // 指向下一个指针
  ngx_pool_large_t     *next;
  // 直接指向内存区域的指针
  void                 *alloc;
};

ngx_pool_t

再来看ngx_pool_t结构体,该数据结构用于表示一个内存池,内存池内部以链表形式来组织数据。如下图:

Aviuieq.png!web

需要说明的是:

  • 内存池内部以链表形式组织起来,完成这个工作的就是前面的ngx_pool_data_t的next成员。
  • current指针,用于表示当前该内存池在使用的pool指针。除了内存池链表的头结点之外,内存池链表其他节点的该指针无效。之所以需要这个指针,就是前面提到的,在某个内存池多次失效的情况下,下一次直接跳过该内存池查找空间,current指针保存当前在内存池链表的哪一个内存池上面查找空间。

有了以上数据结构的了解,从内存池分配内存的流程就很简单了:

FbIB7jY.png!web


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK