ngx_cycle_t是Nginx运行时的“主周期对象”,代表一次完整配置加载、模块初始化与工作进程启动过程,其生命周期由内存池统一管控,初始化通过ngx_init_cycle()创建专属pool并填充模块上下文,重载时双cycle并行过渡,销毁依赖pool释放而非直接free结构体。

ngx_cycle_t 是 Nginx 运行时的“主周期对象”,它不单纯是个全局变量,而是代表一次完整的配置加载、模块初始化与工作进程启动过程。它的生命周期严格绑定于 Nginx 主流程,从启动到重载再到退出,全程由内存池和引用关系控制,而非简单 static 全局驻留。
初始化:从 main() 到 ngx_init_cycle()
main() 函数执行后,立即调用 ngx_init_cycle(&init_cycle),传入一个预初始化的临时 cycle(含 prefix、conf_file 等基础路径参数)。该函数内部:
- 创建专属内存池 pool,后续所有 cycle 相关结构(包括 conf_ctx 数组、模块上下文、监听数组等)均从此池分配
- 按编译时注册的核心模块数量(ngx_core_module_n)分配 conf_ctx 指针数组,类型为 void ***
- 遍历所有核心模块,依次调用其 create_conf 回调,生成并存入各自 xxx_conf_t 结构体指针
- 完成 connections、listening、open_files 等运行时资源的初始化
重载:SIGHUP 触发双 cycle 并行
收到 SIGHUP 信号时,master 进程不销毁当前 cycle,而是启动新一轮 ngx_init_cycle() 创建新 cycle:
- 新 cycle 拥有全新内存池、全新 conf_ctx 及全部模块新配置上下文
- 旧 cycle 仍被正在运行的 worker 进程持有(通过 ngx_cycle 全局指针的原子切换前),确保请求处理不中断
- worker 完成当前请求后,在事件循环空闲时检查 cycle 是否已更新,逐步过渡到新上下文
- 所有 worker 切换完成后,旧 cycle 的内存池才被整体释放
销毁:仅在进程退出或显式清理时发生
ngx_cycle_t 本身不提供显式 destroy 接口,其销毁完全依赖内存池生命周期:
- worker 进程退出时,自动释放其持有的 cycle->pool,连带 conf_ctx 数组、各模块配置结构体、connections 数组等一并回收
- master 进程正常退出前,会释放 init_cycle.pool(即最初那个临时 cycle 的池)
- 没有引用的 cycle 实例(如重载中废弃的旧 cycle)一旦无 worker 持有,其 pool 就不再被访问,等同于逻辑销毁
关键细节:为什么不能直接 free(ngx_cycle)?
ngx_cycle 是 volatile 全局指针,指向的结构体本身不 malloc 分配,而是嵌入在 cycle->pool 内存块中:
- 结构体实例(如 init_cycle)是栈变量或静态分配,但其字段(如 conf_ctx、connections)全部指向 pool 中的动态内存
- 直接 free(ngx_cycle) 会导致悬垂指针,且遗漏 pool 中大量子资源
- 正确做法永远是释放 cycle->pool,由内存池统一回收整块区域
整个生命周期设计以“零拷贝过渡”和“无锁读多写少”为原则,既保证热重载安全,又避免频繁分配释放开销。不复杂但容易忽略。


















