背景: 这熟悉的线条. 请求量没啥波动, 不用怀疑, 就是内存泄露了.

C++内存泄露排查的一个案例_单线程


方案一 ValgrindValgrind可以用来检测是否有非法使用内存的问题, 如: 访问未初始化的内存,访问数组越界, 忘记释放动态内存的问题;

首先需要定位是哪个进程的内存泄露. 使用top命令, 然后shift+m按照内存排序, 找到%MEM最高(或上升最快的)进程(RES). 测试机可复现, 后续步骤测试机完成.

2.安装valgrind包. 可以直接在编译程序时, 加上-g选项. 如下图为例:

C++内存泄露排查的一个案例_开发语言_02

gcc -g -o test test.cpp 
valgrind --tool=memcheck --leak-check=full  ./test

由于我们的是spp框架(开源github可看源码): 所以就手动启动的proxy进程.

3.使用valgrind包启动一个worker进程. 进入到服务的bin目录下执行:

../../valgrind-1.0/bin/valgrind --tool=memcheck --leak-check=full --log-file=valgrind.log ./spp_xxx_worker ../etc/spp_worker1.xml

启动报错:

valgrind: failed to start tool ‘memcheck’ for platform ‘amd64-linux’: No such file or directory

执行命令:

export VALGRIND_LIB=/usr/local/services/valgrind-1.0/lib/valgrind/
  1. 发送请求. 待返回结果后, 调valgrind的进程号, 执行:
kill -10 pid
  1. kill之后查看valgrind.log (还以上图test.cpp为例)

    左边类似行号的数字(22939)表示的是ProcessID; 上面的HEAP SUMMARY, 会显示valgrind发现的内存问题, 堆栈信息, 和具体的代码行数. 最下面的LEAK SUMMARY是个问题汇总. 不过在实际执行中, 因为我们会跑全量的请求. 所以不会这么整齐, 不过搜索关键字, 还是可以看到有用的信息的.

方案二 core文件

1.这个也是在网上搜的一个方法, 首先和思路一样, 都是要寻找升的快的进程. 通过top命令;

2.定位内存泄露的地址范围; 通过pmap -x ${pid} 查看内存情况. 这里我通过spp的配置, 只起一个worker进程, 也就是单线程排查. 通过pmap -x ${pid} 的结果, 可以找到占用多的块.

3.导出内存中的内容. gcore ${pid} ; 通过gdb关联的spp_worker 和coredump文件.

gdb spp_worker(xxx) core.2005(pid)
info proc mappings
dump binary memory result.bin ${start addr} ${start addr}  (eg:dump其中一部分即可)
vim result.bin (使用 :%!xxd 的方式查看内容)

理论上在这个文件中, 可以到可读的, 有意义的字段, 再根据代码去定位.