Rust内存泄漏排查
Contents
原因
Rust 通常情况下, 不会有内存泄漏的. 毕竟是号称内存安全的语言. 如果不幸出现了. 那可以按以下思路排查
- 使用了
unsafe
代码导致. 这种几乎是99%
的原因 - 其他情况还没遇到过
^_^
示例代码
在迁移公司的一个项目到 Rust 体验的时候, 加了下以的代码
pub fn keep_topn_object<T>(list: &mut Vec<T>, max: usize) {
if list.len() <= max {
return;
}
unsafe {
list.set_len(max);
}
}
代码的本意是想将 list
变量只保留前 max
个元素.
发现过程
通过 wrk
来进行压测时, 通过 HTOP
发现 VIRT
和 RES
不断增加.
定位代码
调试前, 修改下系统的设置
echo 0 > /proc/sys/kernel/yama/ptrace_scope
echo 0 > /proc/sys/kernel/kptr_restrict
然后 Rust 在编译时, 加上 debug 信息, 或者就直接以 cargo run
来运行也可. 如果是 --release
则加上以下配置
[profile.release]
debug=true
- 通过
pmap
定位内存地址. 假设你的进程 PID 为 1234 . 则通过pmap -x 1234 > /tmp/mem.1
- 进行
wrk
压测 - 再次执行
pmap
定位内存地址.pmap -x 1234 > /tmp/mem.2
- 比较差异.
diff /tmp/mem.1 /tmp/mem.2
. 查看差异明显的内存地址位置.假设是7fc50043f000
- 查看上面起始地址的内存段.
cat /proc/1234/maps
,找到上面7fc50043f000
内存地址范围. 假设查到的是7fc50043f000-7fc50044f000
- 通过
gdb attach 1234
链接到进程 - 执行 gdb 的命令
dump memory /tmp/pid1234.bin 0x7fc50043f000 0x7fc50044f000
(注意, 要是0x
开头) - 然后通过
strings /tmp/pid1234.bin | less
可以慢慢看到泄漏的内容
我这里的实际情况时, HTTP 请求的内容有一个 ID 标识, xxxxxxxx
, 然后 strings /tmp/pid1234.bin | grep xxxxxxxx | wc -l
看到的行数跟请求数差不多, 可以发现到, 实际是这块相关的内存泄漏了, 而原因正是上面的 unsafe
代码导致的. 修改为
pub fn keep_topn_object<T>(list: &mut Vec<T>, max: usize) {
if list.len() <= max {
return;
}
list.truncate(max);
}
即可