Pmap可以查看堆地址信息(程序中new/malloc出来的空间),然后gdb调试查看堆较大的内存块数据信息。(本次测试只是使用了这个功能,是否还有其他牛逼的功能不知道)
- 编写测试代码
#include <iostream>
#include <string>
#include <stdio.h>
class mem_test
{
public:
mem_test()
{
m_buffer = new char[1000*2000];
printf("memory test address: %p\n", m_buffer);
memcpy(m_buffer, "xiagaodedaqiqiu", 20);
}
private:
char *m_buffer;
};
void mem_leak()
{
char *buffer = new char[1024*1024];
printf("memory leak function address: %p\n", buffer);
memcpy(buffer, "wqb5", 5);
}
int main()
{
mem_leak();
mem_test *ptr = NULL;
for(int i = 0; i < 20; i++)
{
ptr = new mem_test;
delete ptr;
}
while(1)
{
}
return 0;
}
- 编译生成文件后执行,输出信息如下
$ ./a.out
memory leak function address: 0x7fdfc426a010
memory test address: 0x7fdfc3382010
memory test address: 0x7fdfc3199010
memory test address: 0x7fdfc2fb0010
memory test address: 0x7fdfc2dc7010
memory test address: 0x7fdfc2bde010
memory test address: 0x7fdfc29f5010
memory test address: 0x7fdfc280c010
memory test address: 0x7fdfc2623010
memory test address: 0x7fdfc243a010
memory test address: 0x7fdfc2251010
memory test address: 0x7fdfc2068010
memory test address: 0x7fdfc1e7f010
memory test address: 0x7fdfc1c96010
memory test address: 0x7fdfc1aad010
memory test address: 0x7fdfc18c4010
memory test address: 0x7fdfc16db010
memory test address: 0x7fdfc14f2010
memory test address: 0x7fdfc1309010
memory test address: 0x7fdfc1120010
memory test address: 0x7fdfc0f37010
- 以此执行下面的命令
- ps -ef|grep a.out 7972 15451 90 14:23 pts/1 00:00:07 ./a.out找到程序的进程号
- gdb attach 7972
- 进入程序之后执行c,然后ctrl +C回到命令输入状态
- shell pmap 7972查看当前程序所有堆地址信息
0000000000400000 4K r-x-- a.out
0000000000600000 4K rw--- a.out
0000000001f2d000 132K rw--- [ anon ]
00007fdfc0f37000 39120K rw--- [ anon ]
00007fdfc356b000 1804K r-x-- libc-2.17.so
00007fdfc372e000 2044K ----- libc-2.17.so
00007fdfc392d000 16K r---- libc-2.17.so
00007fdfc3931000 8K rw--- libc-2.17.so
00007fdfc3933000 20K rw--- [ anon ]
00007fdfc3938000 84K r-x-- libgcc_s-4.8.5-20150702.so.1
00007fdfc394d000 2044K ----- libgcc_s-4.8.5-20150702.so.1
00007fdfc3b4c000 4K r---- libgcc_s-4.8.5-20150702.so.1
00007fdfc3b4d000 4K rw--- libgcc_s-4.8.5-20150702.so.1
00007fdfc3b4e000 1028K r-x-- libm-2.17.so
00007fdfc3c4f000 2044K ----- libm-2.17.so
00007fdfc3e4e000 4K r---- libm-2.17.so
00007fdfc3e4f000 4K rw--- libm-2.17.so
00007fdfc3e50000 932K r-x-- libstdc++.so.6.0.19
00007fdfc3f39000 2044K ----- libstdc++.so.6.0.19
00007fdfc4138000 32K r---- libstdc++.so.6.0.19
00007fdfc4140000 8K rw--- libstdc++.so.6.0.19
00007fdfc4142000 84K rw--- [ anon ]
00007fdfc4157000 136K r-x-- ld-2.17.so
00007fdfc426a000 1048K rw--- [ anon ]
00007fdfc4376000 8K rw--- [ anon ]
00007fdfc4378000 4K r---- ld-2.17.so
00007fdfc4379000 4K rw--- ld-2.17.so
00007fdfc437a000 4K rw--- [ anon ]
00007fff3a1bb000 132K rw--- [ stack ]
00007fff3a1e0000 8K r-x-- [ anon ]
ffffffffff600000 4K r-x-- [ anon ]
从上面的输出信息可以到有一块大概400k左右的内存块地址,和程序中创建的地址差不多大小(1000*2000*20)
1、x/20s 0x00007fdfc0f37000
0x7fdfc0f37000: ""
0x7fdfc0f37001: ""
0x7fdfc0f37002: ""
0x7fdfc0f37003: ""
0x7fdfc0f37004: ""
0x7fdfc0f37005: ""
0x7fdfc0f37006: ""
0x7fdfc0f37007: ""
0x7fdfc0f37008: "\002\220\036"
0x7fdfc0f3700c: ""
0x7fdfc0f3700d: ""
0x7fdfc0f3700e: ""
0x7fdfc0f3700f: ""
0x7fdfc0f37010: "xiagaodedaqiqiu"
0x7fdfc0f37020: ""
0x7fdfc0f37021: ""
0x7fdfc0f37022: ""
0x7fdfc0f37023: ""
0x7fdfc0f37024: ""
从输出信息可以看到在pmap输出的地址偏差16字节出有用户创建的堆地址
2、x/20s 0x00007fdfc0f37000+1000
(gdb) x/20s 0x00007fdfc0f37000+1000
0x7fdfc0f373e8: ""
0x7fdfc0f373e9: ""
0x7fdfc0f373ea: ""
0x7fdfc0f373eb: ""
发现其他创建的19个堆地址并不是连续的,所有通过地址+1000并不能找到下一个用户创建的堆地址,相反执行-1000的话直接报错(不知为何),0x7fdfc0f37010地址和日志最后一行打印的地址也是对应的。
同样的方式从代码实现可以知道我们还泄露了一个1024*1024字节的内存块,从pmap输出信息可以知道:
00007fdfc426a000 1048K rw--- [ anon ]
猜测这个就是用户创建的内存空间,然后同样的方式找到内存空间的信息
(gdb) x/20s 0x00007fdfc426a000
0x7fdfc426a000: ""
0x7fdfc426a001: ""
0x7fdfc426a002: ""
0x7fdfc426a003: ""
0x7fdfc426a004: ""
0x7fdfc426a005: ""
0x7fdfc426a006: ""
0x7fdfc426a007: ""
0x7fdfc426a008: "\002\020\020"
0x7fdfc426a00c: ""
0x7fdfc426a00d: ""
0x7fdfc426a00e: ""
0x7fdfc426a00f: ""
0x7fdfc426a010: "wqb5"
0x7fdfc426a015: ""
0x7fdfc426a016: ""
0x7fdfc426a017: ""
0x7fdfc426a018: ""
0x7fdfc426a019: ""
同样在偏移16字节出有用户创建的内存空间,和日志打印对比也是对应的。
通过以上方式可以处理部分内存泄露的问题,关键主要有两点,1、能通过pmap找到内存卡地址,这里由于很明显程序创建了一个20个20k大小的空间未释放,然后pmap输出了一个大小差不多400k的快地址,那么很容易对应到泄露源地址。2、找到地址之后,能通过地址的数据内容对应到代码中的数据结构,这里因为程序中将buffer初始化了“xiagaodaqiqiu”这个字符串也是很容易就找到了