#define NGX_ALIGNMENTsizeof(unsigned long)// 8static void *ngx_palloc_block(ngx_pool_t *pool, size_t size){u_char*m;size_tpsize;ngx_pool_t*p, *new;psize = (size_t) (pool->d.end - (u_char *) pool);// 每一个内存池的大小都相同m = ngx_memalign(NGX_POOL_ALIGNMENT, psize, pool->log);// 16 字节对齐申请if (m == NULL) {return NULL;}new = (ngx_pool_t *) m;new->d.end = m + psize;new->d.next = NULL;new->d.failed = 0;m += sizeof(ngx_pool_data_t);m = ngx_align_ptr(m, NGX_ALIGNMENT);new->d.last = m + size;for (p = pool->current; p->d.next; p = p->d.next) {if (p->d.failed++ > 4) {pool->current = p->d.next;}}p->d.next = new;// 尾插法插入至链表末端return m;}
分配一块内存池后逻辑结构如下:
文章插图
大块内存申请大块内存是通过 large 连接的,并且都属于 ngx_create_pool 返回的 ngx_pool_t 结构 。malloc 分配的内存由一个 ngx_pool_large_t 节点来挂载,而这个 ngx_pool_large_t 节点又是从小块内存池中分配的 。
- 为避免large链表长度过大导致在遍历寻找空闲挂载节点耗时过长,限制了遍历的节点为3,如果没有满足要求则直接分配
- 头插法 插入至large链表中,新的节点后面也是最先被访问
static void *ngx_palloc_large(ngx_pool_t *pool, size_t size){void*p;ngx_uint_tn;ngx_pool_large_t*large;p = ngx_alloc(size, pool->log);// 调用 mallocif (p == NULL) {return NULL;}n = 0;for (large = pool->large; large; large = large->next) {// 从large 中链表中找到 alloc 为 NULL 的节点,将分配的内存挂在该节点上if (large->alloc == NULL) {large->alloc = p;return p;}if (n++ > 3) {// 为了避免过多的遍历,限制次数为 0break;}}// 当遍历的 ngx_pool_large_t 节点中 alloc 都有指向的内存时,从小块内存中分配一个 ngx_pool_large_t 节点用于挂载新分配的大内存large = ngx_palloc_small(pool, sizeof(ngx_pool_large_t), 1);if (large == NULL) {ngx_free(p);return NULL;}large->alloc = p;large->next = pool->large;// 头插法 插入至大块内存链表中pool->large = large;return p;}
第一次大块内存分配后的结构如下:文章插图
完整内存池结构逻辑
- 所有的内存池结构都通过 d.next 连接
- 前两个内存池结构的 current 都指向第三个内存池结构
- 所有的 ngx_pool_large_t 节点都是从小内存池中分配的
- 所有的 ngx_pool_large_t 节点都是连接在首个内存池结构上的
- ngx_pool_large_t 节点的 alloc 被释放但 ngx_pool_large_t 节点不回收
文章插图
总结ngx_pool_t 内存分配方面
- 通过 current 和 d.next 来访问其他的内存池结构
- 插入方式
- 小块内存池通过尾插法插入至内存池链表的尾端
- 大块内存通过头插法插入至large链表的首部
- 限制次数
- 小内存分配失败(failed)次数大于4次后就不再作为分配内存的池子了
- 大内存只寻找 large 链表中前三节点是否可以挂载新分配的内存
- 内存对齐,多处内存对齐减少内存跨 cache 的数量
推荐阅读
- Nginx,一看就会
- 技术大佬教你如何使用Nginx在公网上搭建加密数据通道?
- 一个线程内存泄漏问题定位过程
- 特斯拉|三元锂不香了!马斯克押宝磷酸铁锂电池:近一半新车用上
- 笔记本|轻至999g!LG 2022款gram笔记本发布:12代酷睿/32G内存/雷电4都有了
- 彻底搞懂Java线程池的工作原理
- Nginx配置知识点梳理
- seo蜘蛛池是什么?seo蜘蛛池原理
- 电池|底盘与电池合二为一!一文了解零跑电池CTC技术
- AMD|AMD老用户最担心的事情来了:Zen 4处理器抛弃DDR4内存被证实