valgrind 内存泄漏_linux C/C++利用进程内存镜像定位内存泄漏

|导语 内存泄漏是c/c++老生常谈的问题了,也有一些比较成熟的工具卸载我们定位内存泄漏问题典型的就有valgrind。该工具需要定位内存泄漏是需要cover对应的业务逻辑才会把内存泄漏地方暴露出来。 这里介绍一种基于运行时进程内存镜像定位内存泄漏问题。

利用进程运行时的内存镜像分析程序是哪个类的实例没有释放,虽然不能做到一针见血找到引起内存泄漏的代码,但是可以利用该方法,缩小的范围。这种方法,不需要触发特定的业务逻辑,只要你的程序已经存在内存泄漏,且内存镜像还存在就可以进行分析。

1)先来模拟内存泄漏的场景。

测试程序:(发现头条不适合做长篇代码的分享,在移动端开长篇代码体验极差,也很难达到预想的效果)

#include #include class T1 { public:  T1(){} virtual ~T1(){} }; int main(int argc,char* argv[]) { for(int i = 0;i < 1000000;i++) { T1 *t = new T1; char *p = (char*)malloc(sizeof(char)); } pause(); //目的是为了能够dump 进程内存镜像 return 0; }

2)编译运行查看内存、内存分布情况:

top -p 5250

PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND

5250 user_00 25 5 77404 61m 756 S 0.0 0.8 0:00.08 a.out

$pmap 5250

下面是该进程的内存分布情况

0000000001e06000 62568K rw--- [ anon ]00007f7022466000 20K rw--- [ anon ]00007f7022bf6000 84K rw--- [ anon ]00007f7022d0b000 20K rw--- [ anon ]00007f7022e26000 16K rw--- [ anon ]00007f7022e2c000 4K rw--- [ anon ]00007fff0a5a3000 84K rw--- [ stack ]00007fff0a5ff000 4K r-x-- [ anon ]ffffffffff600000 4K r-x-- [ anon ]

通过上图的内存分布可以看到,这块匿名「anon】的内存区域比较大,其他小的[anon]不要考虑(抓住主要矛盾)

0000000001e06000 62568K rw--- [ anon ]

3)分析内存镜像

接下来就是借助万能的gdb把这块内存中存储的信息输出来。通过gdb 生成core:(生成core文件主要是防止进程的内存比较大的时候,后续的分析操作会导致进程长时间没有响应,如果你的进程有单独的父进程管理很有可能会因为超时被kill掉)

$gdb attach 5250

(gdb)gcore

执行以上命令,在当前目录下生成core.5250(具体看系统core文件名配置的规则)。

用gdb 打开core文件,将0000000001e06000 起始的内存内容输出到文件中:

gdb -c core.5250 mem_leak(gdb) set height 0(gdb) set logging onCopying output to gdb.txt.(gdb) x/8008704a 0x0000000001e06000

set logging on 将gdb操作输出到日志文件中,方便后续分析。

x/8008704a

格式说明:

62568=1e06000H

8008704=62568*1024/8 (因为demo是64 bit所以要/8byte)

a为gdb输出其中一种格式

最后就是分析上面生成的gdb.txt(如果这块内存比较大的话,输出需要很长时间),直接看的话有点懵逼:

9d8f1fdb081a66dd688e85a88ef33271.png

Fig1 转换前

所以需要做一下转换:

cat gdb.txt|c++filt >demo.txt

6c2919dc7ea56033303dfeac2cd3c809.png

Fig 2 转换后

通过统计demo.txt 中各个对象的个数来判断是否是该对象存在内存泄漏,当然也有可能实际上你的程序就是这么多正常的对象,所以需要理智的判断。

cat demo.txt|awk 'BEGIN{stat[""]=0}{stat[$5]++}END{for(i in stat) print i"="stat[i]}'

=2295782

T1+16>=765261

测试程序中是这个类T1的对象存在内存泄漏,剩下的就是体力活了,看这个类哪里new了。。

这种方法的不足之处:

他依赖于类的实例中的虚函数表,如果是原生类型(int、char)这种那么这种方法也就无能为力,毕竟每种方案都不是十全十美。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值