Rust程序使用bcc stackcount生成内存火焰图的方法
问题原因
- 命令中使用的宽泛正则
.*malloc.*会默认匹配内核态、进程加载的所有二进制/共享库中带malloc字样的符号,其中大量符号是内联未导出、不存在、或不允许挂载探针的,因此出现大量cannot attach kprobe, Invalid argument报错,同时真正的内存分配入口(glibc的malloc)的探针挂载被无效匹配项干扰,导致采集不到有效数据。 - 你虽然配置了Rust强制开启帧指针,但没有指定探针挂载的目标对象:Rust程序动态链接的libc
malloc符号不存在于主程序二进制中,而是在libc共享库的PLT跳转段,全局模糊匹配时很容易漏挂这个核心探针点。 - 你贴的
.cargo/config配置存在引号不配对的笔误风险,会导致帧指针配置不生效,后续无法正确采集完整用户态调用栈。
正确操作步骤
- 修正Rust编译配置
打开项目下的.cargo/config,修正rustflags的引号配对问题,确保帧指针强制开启配置生效:
[build] rustflags = "-C force-frame-pointers=yes"
在项目根目录执行cargo build --release重新编译二进制,启动目标程序后记录进程PID。
- 定位目标进程加载的libc路径
执行如下命令拿到进程依赖的libc共享库实际路径(不同发行版路径存在差异):
cat /proc/<你的进程PID>/maps | grep libc.so.6 | head -n 1 | awk '{print $6}'
x86_64架构Debian/Ubuntu系的默认路径通常为/lib/x86_64-linux-gnu/libc.so.6。
- 执行修正后的stackcount采集命令
不要使用全局模糊正则,显式指定探针挂载到libc库,匹配内存分配相关函数,避免无效挂载:
# 采集malloc/calloc/realloc/free的调用栈,输出折叠格式重定向到文件 sudo stackcount-bpfcc -p <你的进程PID> -U -d -r '^malloc$|^calloc$|^realloc$|^free$' <上一步拿到的libc路径> > rust_mem_stacks.folded
命令执行后等待业务逻辑跑完你需要观测的内存分配场景,按Ctrl+C结束采集,此时不会再出现kprobe挂载报错,会正常写入调用栈数据到折叠文件中。
如果你使用了非默认内存分配器(比如jemalloc、mimalloc),需要将挂载目标换成对应分配器的共享库路径,匹配对应分配函数的符号,否则无法采集到分配栈。
- 生成内存火焰图
将采集到的折叠栈文件传入FlameGraph工具链的flamegraph.pl脚本,指定内存配色生成svg图:
./flamegraph.pl --color=mem rust_mem_stacks.folded > rust_memory_flamegraph.svg
常见排查点
- 如果采集到的栈只有地址没有符号,检查你的系统是否安装了libc的debug符号包,Rust二进制是否保留了符号表(不要用
strip过度裁剪release二进制)。 - 如果栈出现截断,确认帧指针配置确实生效,可以用
readelf -p .comment <你的二进制路径>检查编译参数,确认包含force-frame-pointers=yes。 - 低版本(<0.18)的bcc工具对Rust编译的二进制uprobe支持存在兼容问题,升级bcc版本到0.18以上即可解决。
内容的提问来源于stack exchange,提问作者elmattic
相关产品推荐
相关产品推荐

