ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

内存悄悄涨 8GB 找不到原因?用 jeprof 给 jemalloc 拍张快照就能定位

内存悄悄涨 8GB 找不到原因?用 jeprof 给 jemalloc 拍张快照就能定位 内存悄悄涨 8GB 找不到原因用 jeprof 给 jemalloc 拍张快照就能定位【免费下载链接】jemalloc项目地址: https://gitcode.com/GitHub_Trending/je/jemalloc上周有个服务在压测后常驻内存从 2GB 一路爬到 10GB重启后一切恢复如初——典型的内存去哪了问题。如果程序链接的是 jemalloc一个为高并发场景优化的 C 内存分配器你可以用它的配套工具 jeprof 给运行中的进程拍一张内存账单快照再用火焰图把占用大头的那几条调用栈直接揪出来。全文按真实排查流程走一遍装好带分析功能的 jemalloc → 让程序吐出快照文件 → 读懂 jeprof 报告 → 画出内存火焰图 → 坐实泄漏最后给出生产环境长期开 profiling 的代价与规避办法。第 1 步编译一个会记账的 jemalloc普通的 malloc 只负责把内存分出去而启用 profiling 的 jemalloc 会额外记录谁、在哪一行、分了多少没还。这一步只需要在 configure 时加一个开关git clone https://gitcode.com/GitHub_Trending/je/jemalloc cd jemalloc ./autogen.sh ./configure --enable-prof --prefix/usr/local/jemalloc make -j4 make install编译出来的库里就带上了 jeprof 需要的采样记账能力jeprof 本体则随make install一起放进bin/目录。验证一下/usr/local/jemalloc/bin/jeprof --version 避坑如果忘了--enable-prof程序照样能跑但 MALLOC_CONF 里写prof:true会被静默忽略快照文件永远不会出现——这是新手最常见的为什么没有输出。可以用jemalloc-config --config | grep prof确认编译选项。接着让目标程序替换掉系统自带的 libc malloc。最简单的方式是加链接参数gcc -g -o myapp myapp.c -L/usr/local/jemalloc/lib -ljemalloc -Wl,-rpath,/usr/local/jemalloc/lib注意这里保留了-g。jeprof 要靠调试符号和 DWARF 信息把地址翻译成文件:行号不带-g的报告里只剩函数名行号定位就没了。第 2 步让程序吐出快照文件.heap 文件运行时通过环境变量告诉 jemalloc 开启记账并指定账单落盘路径export MALLOC_CONFprof:true,lg_prof_sample:20,prof_prefix:/tmp/prof/myapp ./myapp这三个参数的作用参数白话解释建议prof:true打开记账总开关必须lg_prof_sample:20平均每分配 2^201MB 随机抽一次样生产可调大到 224MB降开销prof_prefix快照文件名前缀指到进程有写权限的目录采样是这里的关键机制jemalloc 不是给每次分配都拍照而是像路口装了一台流量摄像头按字节数概率性地随机抽拍所以开销可控代价是结果是统计值而非精确值这正是它适合在生产环境跑的原因。程序正常退出时jemalloc 会自动按前缀写出一个myapp.pid.时间戳.i序号.heap文件。中途想抓拍也可以不退出进程#include jemalloc/jemalloc.h char path[256]; mallctl(prof.dump, path, NULL, NULL, 0); // 立即生成一个 .heap 快照⚠️ 避坑快照文件由进程自己写盘所以进程必须对prof_prefix目录有写权限且目录所在磁盘要有剩余空间——权限不足时同样表现为静默无文件。第 3 步读懂 jeprof 文本报告拿到.heap文件后最常用的是--text也叫 top 视图按占用降序列出调用栈顶部函数jeprof --text /tmp/prof/myapp /tmp/prof/myapp.12345.1710000000.i1.heap输出大致长这样Total: 8.2 G 0.551 46.2% 46.2% 0.551 46.2% parse_request_body 0.302 25.3% 71.5% 0.302 25.3% build_user_cache 0.089 7.4% 78.9% 0.089 7.4% serialize_json四列数字是 jeprof 的固定口径flat该函数自己直接分配的内存不含它调用的下游flat%flat 占总量百分比cumulative%从根到它这一路的累计占比用来判断这条调用链整体有多重cumulative该函数及其所有下游的总分配量。看报告的技巧先看 cumulative 找重的调用链再看 flat 找真正动手分配的叶子函数。上面例子里parse_request_body自己就吃了 46%优化目标很明确。两个常用变体# 精确到源码行号需要 -g 编译 jeprof --text --lines /tmp/prof/myapp /tmp/prof/myapp.*.heap # 只看与某个函数相关的栈比如排查 HTTP 请求路径 jeprof --text --focusrequest /tmp/prof/myapp /tmp/prof/myapp.*.heap第 4 步一张内存火焰图看全局文本报告适合看单点但整条调用链的重心在哪用图更直观。jeprof 依赖 graphviz装好后一条命令出图# Ubuntu/Debian 示例 sudo apt install -y graphviz jeprof --svg /tmp/prof/myapp /tmp/prof/myapp.*.heap mem.svg # 想要 PDF 格式调用图则换成jeprof --pdf ...生成的 SVG 里横轴宽度代表该栈帧占用的内存比例越宽越重纵轴是调用深度父函数在下、被调方在上。排查时的动作是从根一路找最宽的山脊再沿着它往下钻到第一个明显变宽的业务函数那就是优化入口。注意火焰图颜色只是用来区分相邻栈帧没有深浅含义别被误导。 对比技巧内存缓慢增长类问题隔一段时间抓两次快照用--diff_base旧文件分析新文件正号行表示这段时间净增的分配增长最快的路径一眼可见。第 5 步坐实内存泄漏前四步能告诉你谁占了内存但泄漏需要额外证据链建议两步走抓基线服务刚启动、流量平稳时 dump 一份.heap作为基线跑压力 二次对比压测一小时后再 dump用 diff 报告看持续净增的部分同时开启泄漏模式MALLOC_CONFprof:true,prof_leak:true,prof_prefix:/tmp/prof/leakprof_leak:true会让程序退出时额外输出一份到死都没 free 的内存清单。结合 mallctl 里的stats.allocated当前在手上没还的字节数观察趋势allocated 随时间单调上涨且与业务数据量无关基本可以定性为泄漏。⚠️ 避坑采样是随机的小对象几十字节的泄漏可能在报告里被摊薄得几乎看不见。如果你怀疑的是小块高频泄漏把lg_prof_sample调小如 18即 256KB 粒度重采一次但采样频率越高开销越大两者要权衡。生产环境长期开 profiling 的代价直接把结论放前面有开销但可控适合默认低频率开着、出问题再加密的策略。CPU/吞吐开销主要来自每次采样时的栈回溯backtrace量级通常在个位数百分比lg_prof_sample每加 1采样间隔翻倍采样开销约减半压测环境建议从 201MB起步大吞吐服务可放宽到 22 甚至更大。内存开销每份被记录的分配栈都要缓存一份调用栈副本采样粒度越细、存活分配越多这笔记账本越大。磁盘开销.heap文件与存活分配规模正相关注意监控prof_prefix所在分区容量并给目录收紧权限快照里含函数名可能泄露内部模块结构。动态开关不必重启进程就能调整——运行时通过 mallctl 修改prof.active可临时开/关采样lg_prof_sample也可热调平时关着、告警时打开是常见的折中做法。另外提醒一句jeprof 输出的是统计采样结果和 Valgrind 那种逐次分配精确跟踪不同别拿它做精确到某个字节的泄漏举证精确排查用它指路、再上针对性手段复核即可。接下来往哪里看仓库里的 doc/jemalloc.xml.in 是完整的 API 与所有prof.*配置项的官方文档源参数语义以它为准采样与记账的核心实现在 src/prof.c 和 src/prof_sys.c想理解为什么报告是长这样可以从这两个文件读起。【免费下载链接】jemalloc项目地址: https://gitcode.com/GitHub_Trending/je/jemalloc创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表