core dump 本身不能直接确认内存碎片化,它仅记录崩溃瞬间的内存快照;但通过分析崩溃是否发生在 ngx_palloc/ngx_pcalloc 内部、large 链表长度、第三方模块 libc 堆分配调用等线索,可反向推断碎片化是否已严重到引发野指针或池误用等下游崩溃。

核心 Dump 本身不能直接确认内存碎片化——它记录的是进程崩溃瞬间的内存快照,而碎片化是运行时长期积累的堆状态,通常不触发崩溃。但结合特定分析路径,你可以从 core dump 中提取关键线索,反向推断碎片是否已严重到影响稳定性。
先确认是不是真发生了碎片化
内存碎片化在 Nginx 中极少直接导致 crash,更常见的是:
- RSS 持续上涨但请求结束后不回落(典型信号)
- 压测中 malloc 耗时突增、系统调用(brk/mmap)频率升高
- valgrind --tool=massif 显示大量细碎 heap allocation 峰
- core dump 的触发原因其实是 野指针访问 或 池指针误用(比如定时器里用了已销毁的 r->pool),而这恰恰是碎片化失控的下游表现
从 core dump 中抓取有效线索
用 gdb 打开 core 文件后,重点检查以下几项:
- 崩溃位置是否在 ngx_palloc / ngx_pcalloc 内部?如果是 last 指针越界、size 计算溢出或 pool->d.last > pool->d.end,说明主池线性区已被反复切割耗尽,被迫频繁切新块——这是小块分配导致内部碎片的直接证据
- 查看 large 链表长度:p ((ngx_pool_t*)$r_pool_addr)->large,若节点数异常高(如数百以上),且每个节点 size 接近 4095 字节,说明大量请求卡在阈值边缘分配,large 链表膨胀拖慢销毁速度
- 检查 backtrace 中是否有第三方模块调用 strdup/asprintf:gdb 中 info sharedlibrary 看是否加载了 lua-nginx-module;bt 全栈中若出现 __libc_malloc、strdup、luaM_realloc_,说明有 libc 堆分配逃逸,这是隐式碎片主因
配合运行时日志交叉验证
Nginx 编译时加 -DNGX_DEBUG_POOL 后,每创建/销毁一个池都会打日志。在 core 产生前,搜日志中的:
- "pool: 0x..., size: 4096, used: XXX" —— 若 used 值普遍偏低(如平均
- "destroy pool" 频次远低于 "create pool",或销毁耗时明显增长(>1ms),提示 large 链表清理压力大
- 大量 "ngx_chain_get_free_buf: no free buf" 日志,说明 chain 复用机制失效,被迫频繁分配新节点
真正有效的排查动作不是只看 core
建议组合使用:
- 压测时用 pmap -x PID 定期采样,观察 anon-rss 是否阶梯式上涨、mmap 区域是否增多
- 用 asan(AddressSanitizer) 重新编译 Nginx,它能捕获 use-after-free 和 heap-buffer-overflow,比 core dump 更早暴露池生命周期错乱
- grep 模块源码:找 malloc/calloc/strdup/asprintf,确认所有临时数据是否都走 pool-aware 接口











