最可靠方式是用Valgrind跟踪单worker进程:编译需带-g -O0调试符号且禁用优化,运行时设master_process off并直启前台worker,再通过专用location触发模块逻辑,结合泄漏日志与debug日志交叉验证。

直接用 Valgrind 跟踪单 worker 进程是最可靠的方式,关键不在“能不能测”,而在“怎么让 Valgrind 看得见、跟得住、判得准”。
编译阶段:必须带调试符号且禁用优化
Nginx 和你的第三方模块都得从源码重新编译,不能用系统包或预编译二进制:
- 配置 Nginx 时加上 --with-debug,并手动修改
objs/Makefile,在所有CFLAGS行末尾追加 -g -O0 -fno-omit-frame-pointer - 第三方模块的
config文件里不能硬编码-O2或调用strip;如果模块用 autotools,也要确保 configure 加上--enable-debug - 验证是否成功:运行
nm -C /opt/nginx-debug/sbin/nginx | grep ngx_http_your_module_handler,能看到函数名而非一堆下划线,说明符号完整
运行阶段:绕过 master,直启前台 worker
Valgrind 跟 master 进程毫无意义,fork 出的 worker 会脱离监控。正确做法是让 Nginx 不启动 master,只跑一个前台 worker:
Linux系统管理专家,覆盖12大模块:用户权限、SSH、存储、网络、systemd、防火墙、日志监控、备份恢复、TLS证书、Ansible、容器、IaC。提供配置、验证、加固、监控、备份、自动化、故障排查、回滚闭环。关键词:useradd、sudo、sshd_config、chmod、SEL...
- 修改
nginx.conf:设置 master_process off;、worker_processes 1;、daemon off; - 用 Valgrind 启动:
valgrind --leak-check=full --show-leak-kinds=all --track-origins=yes --log-file=valgrind.log /opt/nginx-debug/sbin/nginx -c /opt/nginx-debug/conf/nginx.conf - 此时进程不会后台化,Ctrl+C 即发送 SIGINT,Nginx 会执行优雅退出,Valgrind 才能捕获完整堆内存快照
触发与验证:精准复现模块逻辑
内存泄漏往往只在特定路径下发生,不能靠随机请求:
- 在配置中明确启用你的模块,并配一个专用
location,比如location /test-module { your_module_on; } - 用 curl 或 wrk 发起至少几十次请求,确保模块核心逻辑(如解析、分配 pool、调用 ngx_palloc)被充分执行
- 观察日志中是否出现类似
definitely lost: 1,024 bytes in 1 blocks的报告,重点看调用栈里是否含你的模块函数名和ngx_palloc/ngx_pcalloc调用链
辅助定位:禁用法 + 日志交叉验证
当 Valgrind 报告模糊或漏报时,用轻量级手段快速缩小范围:
- 逐个注释
load_module指令,只留目标模块,重启后用ps aux --sort=-%mem | head -5观察 RSS 是否持续上涨 - 开启 Nginx debug 日志:
error_log logs/error.log debug;,在模块代码中加入ngx_log_debug打印内存分配点(如 pool 地址、size),对比请求前后是否遗漏ngx_pfree或误用了 long-lived pool - 若泄漏仅在高并发下暴露,Valgrind 性能损耗太大,可换用 AddressSanitizer(需重新编译,性能损失仅约 2 倍),命令加
-fsanitize=address -fno-omit-frame-pointer

















