排查Nginx模块内存泄漏的核心是快速隔离、精准复现、工具直击分配源头:先注释load_module并reload验证RSS是否停止增长,再单worker前台运行+debug日志触发特定路径,用Valgrind盯ngx_palloc_large调用栈及内存池生命周期错误,最后通过wrk压测比对VmRSS变化验证修复效果。

排查 Nginx 模块引起的内存泄漏,核心是“快速隔离 + 精准复现 + 工具直击分配源头”,不是盲目查代码,而是用系统行为反推问题模块。
第一步:停用模块,确认是否真由它引起
内存持续上涨但配置未变,优先怀疑新引入或刚更新的第三方模块。操作很简单:
- 打开 nginx.conf,把疑似模块的 load_module 行全部注释掉(例如:#load_module modules/ngx_http_sub_filter_module.so;)
- 执行 nginx -t 验证语法,再 nginx -s reload
- 用 ps aux --sort=-%mem | head -5 或 top -p $(pgrep nginx) 持续观察 worker 进程 RSS 内存 5–10 分钟
- 如果内存停止上涨,说明泄漏大概率来自被禁用的某个模块;再逐个启用、逐个验证,缩小范围
第二步:单 worker 前台运行,只触发目标逻辑
模块泄漏往往只在特定请求路径下触发(比如含 sub_filter 的 location、Lua 脚本、或带特殊 header 的请求)。必须让分析工具真正“看到”它:
- 在配置中设置:master_process off;、worker_processes 1;、daemon off;
- 开启 debug 日志:error_log logs/error.log debug;
- 只发能激活该模块的请求(例如访问 /api/subs,或加头 X-Process-Lua: true)
- 用 Ctrl+C 退出,不要 kill -9——这是让 Valgrind 完整捕获释放阶段的关键
第三步:用 Valgrind 盯调用栈,重点看内存池生命周期
Valgrind 是定位 C 模块内存泄漏最可靠的工具,但需满足两个前提:Nginx 和模块都带调试符号(-g -O0),且运行在单 worker 前台模式。
- 启动命令示例:valgrind --leak-check=full --show-leak-kinds=all --log-file=valgrind-out.txt /opt/nginx-debug/sbin/nginx -c /opt/nginx-debug/conf/nginx.conf
- 报告出来后,搜索 ngx_palloc_large——如果大量泄漏块都从这里分配,且调用栈含你的模块名(如 ngx_http_myfilter_handler),基本锁定
- 检查模块源码是否在 handler 或 filter 链路里调用了 ngx_palloc/ngx_pcalloc,但没注册 ngx_pool_cleanup_t 回调
- 特别注意:是否把长期存活的数据(如缓存结构体)错误地分配在 request pool 上——request 结束就销毁,但数据本该活到 server 重启
第四步:压测对比修复效果
改完代码不能只看一次请求,要模拟真实负载:
- 用 wrk 发 1000+ 次相同请求(确保每次都走同一模块逻辑)
- 压测前记下:cat /proc/$(pgrep nginx)/status | grep VmRSS,结束后再查,差值应趋近于 0
- 若仍缓慢上涨,说明还有 cleanup 漏洞,或存在未显式释放的 shared memory 或全局缓存结构


















