nginx event loop 本身不分配内存,但其运行方式深刻影响内核与用户态内存使用:需控制 epoll 监听项规模、精简连接生命周期内存开销、合理配置共享内存区,并协同内核参数缓解隐式内存压力。

Nginx 的 Event Loop 本身不直接分配内存,但其运行方式深刻影响内核与用户态的内存使用模式。优化重点不在“给 event loop 分配更多内存”,而在于减少它触发的低效内存行为——比如 epoll 控制块膨胀、连接缓冲区冗余、共享内存争用和临时对象堆积。
控制 epoll 监听项规模,降低 eventpoll 内存驻留
每个被 epoll_ctl 添加的文件描述符(如 client socket)都会在内核中生成一个 struct epitem,单个约占用 128–200 字节。大量空闲或短命连接会持续占用 eventpoll 内存,且无法由 Nginx 主动释放。
- 用
listen ... deferred;减少 accept 队列积压,避免瞬间涌入大量连接并批量注册 epoll - 调低
keepalive_timeout和client_header_timeout,加速连接关闭,促使内核及时回收 epitem - 启用
reset_timedout_connection on;,主动清理超时连接,防止 stale fd 持续挂载在 epoll 中 - 确保
fs.epoll.max_user_watches足够(建议 ≥ worker_processes × worker_connections × 1.5),避免因上限触发频繁的添加/删除抖动
精简连接生命周期中的内存开销
每个活跃连接在用户态会分配请求缓冲区、SSL 上下文、重定向临时结构等。这些不是 event loop “分配”的,但均由 event loop 触发创建。
- 设小而合理的
client_body_buffer_size(如 16k),避免大缓冲区默认预分配 - 静态资源服务开启
sendfile on;和tcp_nopush on;,跳过用户态拷贝,减少 socket buffer 和 page cache 压力 - 对已知重定向路径(如 HTTP→HTTPS)优先用
return 301,而非rewrite ... redirect,省去 PCRE 解析和字符串拼接内存分配 - 恶意路径拦截用
return 444;,不构造响应体,彻底跳过 buffer 分配与 sendfile 调度
合理配置共享内存区,避免 slab 碎片与锁竞争
Nginx 的 shared memory(如限流 zone、cache keys_zone、SSL session cache)由 master 进程统一创建,worker 共享访问。配置不当会导致内存浪费或原子操作阻塞。
- 按实际 key 数量估算大小:每 1MB keys_zone 可存约 8000–12000 个 key;限流 zone 每 1MB 支持约 16000 个 IP 计数器
- 避免“宁大勿小”:过大造成 slab pool 空闲块碎片化,过小引发高频淘汰与哈希冲突
- 所有写操作必须使用模块提供的原子接口(如
ngx_atomic_fetch_add())或显式加锁(ngx_shmtx_lock),不能裸写指针偏移 - 上线前用真实流量分布压测验证,不可依赖理论值
协同内核参数,缓解隐式内存压力
Event Loop 响应延迟常源于内存子系统卡顿,例如 kswapd 回收页、direct reclaim 阻塞 socket 创建等,这些虽不属 Nginx 管理,却直接影响 event loop 流畅度。
- 设
vm.swappiness = 1并保留 swap 分区,避免极端内存压力下直接阻塞 - 监控
/proc/meminfo中PageTables和DirectMap是否异常增长,过高说明页表开销过大 - 调大
net.core.rmem_max和net.core.wmem_max前确认物理内存余量,防止预留过多加剧 OOM 风险 - 绑定 worker 到专用 CPU 核心(
worker_cpu_affinity auto;),减少跨核缓存失效带来的间接内存带宽损耗











