nginx/内存池与请求生命周期

按请求生命周期批量管理小对象内存

nginx 将小额分配变成池内游标推进,并以池的生命周期统一释放;较大的分配另建记录管理。

release-1.26.3内存管理核验 2026-10-09

工程问题#

解析和处理 HTTP 请求会产生许多生命周期相近的小对象;逐个分配、追踪和释放会增加管理工作。

实际实现#

ngx_palloc 对不超过 pool->max 的分配调用 ngx_palloc_small:从 current 块开始,对齐 d.last 并检查空间,成功便推进游标。块不够时遍历后续块或分配新块;大对象由 ngx_palloc_large 单独分配并登记。

处理流程#

  1. 按大小与调试配置选择小对象池路径或大对象路径
  2. 对齐当前块游标,空间足够则返回旧游标并推进 d.last
  3. 空间不足时找后续池块或扩展;池销毁时运行清理回调并释放池块与大对象

源码片段#

固定版本 · 原文摘录
src/core/ngx_palloc.crelease-1.26.3 · L154–L174
查看原文件
154    p = pool->current;155156    do {157        m = p->d.last;158159        if (align) {160            m = ngx_align_ptr(m, NGX_ALIGNMENT);161        }162163        if ((size_t) (p->d.end - m) >= size) {164            p->d.last = m + size;165166            return m;167        }168169        p = p->d.next;170171    } while (p);172173    return ngx_palloc_block(pool, size);174}
ngx_palloc_small

从 current 块取 d.last,按需对齐后检查剩余空间;命中便推进游标。否则沿块链表继续找,最终进入扩展池块的慢路径。

展示小对象分配的主体;大小分流、大对象登记和销毁逻辑在同一原始文件中。

收益与取舍#

工程分析

带来的收益

  • 小对象命中现有块时只需对齐、边界检查和游标更新
  • 把大量对象的回收绑定到同一所有者,减少逐对象释放步骤

付出的代价

  • 小对象通常不能用 ngx_pfree 单独归还,内存会保留到池重置或销毁
  • 当前块空间不足时仍会遍历或分配,不能把所有分配都视为严格 O(1)
  • 对象引用不得超出池的生命周期;对齐与未使用尾部也会消耗空间

可比较的选择

逐对象 malloc / free允许独立释放不同生命周期对象,但需要更细粒度的所有权与释放管理。

Slab / 对象缓存适合反复复用固定规格对象;与按生命周期整体释放的内存池目标不同。

版本与适用范围#

nginx release-1.26.3 的 ngx_pool_t;请求可持有自己的 pool,其他配置与连接对象也会使用池。大对象单独分配;NGX_DEBUG_PALLOC 可绕开常规小对象池路径。

参考来源#

源码、官方文档与原始论文
01
nginx · ngx_palloc / ngx_palloc_small

src/core/ngx_palloc.c · ngx_palloc / ngx_palloc_small

源码release-1.26.3
02
nginx · ngx_destroy_pool / ngx_pfree

src/core/ngx_palloc.c · ngx_destroy_pool / ngx_pfree

源码release-1.26.3
03
nginx · rrp = ngx_palloc(r->pool, …)

src/http/ngx_http_upstream_round_robin.c · rrp = ngx_palloc(r->pool, …)

源码release-1.26.3

相关实现与比较#

4 个相关案例
14 个匹配案例