gdb查看堆内存以及内存泄漏的一种定位方法

6/26/2022 知识

# 方法

循环分配10000个类对象 然后查看内存空间源码在最下面

对c++类的虚函数有基本了解

# 编译命令

g++ -o memtest memtest.cpp -g -O0
1

# 直接开始

@luo:~/workspace/memtest# gdb memtest <----------------------- 使用gdb 调试memtest
GNU gdb (Ubuntu 9.2-0ubuntu1~20.04.1) 9.2
...
...
Reading symbols from memtest...
(gdb) r <------------------------------------------------------开始运行
Starting program: /root/workspace/memtest/memtest 
terminate called after throwing an instance of 'std::bad_alloc'
  what():  std::bad_alloc

Program received signal SIGABRT, Aborted.
__GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:50
50	../sysdeps/unix/sysv/linux/raise.c: No such file or directory.
(gdb) info proc <---------------------------------------------查看当前进程信息
process 2132 <------------------------------------------------ 当前进程pid
cmdline = '/root/workspace/memtest/memtest'
cwd = '/root/workspace/memtest'
exe = '/root/workspace/memtest/memtest'
(gdb) shell pmap -x 2132 <------------------------------------ 使用pmap查看内存映射
2132:   /root/workspace/memtest/memtest
Address           Kbytes     RSS   Dirty Mode  Mapping
0000555555554000       4       4       4 r---- memtest
0000555555555000       4       4       4 r-x-- memtest
0000555555556000       4       4       0 r---- memtest
0000555555557000       4       4       4 r---- memtest
0000555555558000       4       4       4 rw--- memtest
0000555555559000     396     324     324 rw---   [ anon ] <------堆内存地址
00007ffff7a7d000      16      16      16 rw---   [ anon ]
00007ffff7a81000      12      12       0 r---- libgcc_s.so.1
00007ffff7a84000      72      72       0 r-x-- libgcc_s.so.1
00007ffff7a96000      16      16       0 r---- libgcc_s.so.1
00007ffff7a9a000       4       4       4 r---- libgcc_s.so.1
00007ffff7a9b000       4       4       4 rw--- libgcc_s.so.1
00007ffff7a9c000      52      52       0 r---- libm-2.31.so
00007ffff7aa9000     668     256       0 r-x-- libm-2.31.so
00007ffff7b50000     612       0       0 r---- libm-2.31.so
00007ffff7be9000       4       4       4 r---- libm-2.31.so
00007ffff7bea000       4       4       4 rw--- libm-2.31.so
00007ffff7beb000     136     136       0 r---- libc-2.31.so
00007ffff7c0d000    1504     848       8 r-x-- libc-2.31.so
00007ffff7d85000     312     172       0 r---- libc-2.31.so
00007ffff7dd3000      16      16      16 r---- libc-2.31.so
00007ffff7dd7000       8       8       8 rw--- libc-2.31.so
00007ffff7dd9000      16      12      12 rw---   [ anon ]
00007ffff7ddd000     600     600       0 r---- libstdc++.so.6.0.28
00007ffff7e73000     964     628       4 r-x-- libstdc++.so.6.0.28
00007ffff7f64000     292     164       0 r---- libstdc++.so.6.0.28
00007ffff7fad000       4       0       0 ----- libstdc++.so.6.0.28
00007ffff7fae000      44      44      44 r---- libstdc++.so.6.0.28
00007ffff7fb9000      12      12      12 rw--- libstdc++.so.6.0.28
00007ffff7fbc000      20      20      20 rw---   [ anon ]
00007ffff7fcb000      12       0       0 r----   [ anon ]
00007ffff7fce000       4       4       4 r-x--   [ anon ]
00007ffff7fcf000       4       4       0 r---- ld-2.31.so
00007ffff7fd0000     140     140      24 r-x-- ld-2.31.so
00007ffff7ff3000      32      32       0 r---- ld-2.31.so
00007ffff7ffc000       4       4       4 r---- ld-2.31.so
00007ffff7ffd000       4       4       4 rw--- ld-2.31.so
00007ffff7ffe000       4       4       4 rw---   [ anon ]
00007ffffffde000     132      12      12 rw---   [ stack ]
ffffffffff600000       4       0       0 --x--   [ anon ]
---------------- ------- ------- ------- 
total kB            6148    3648     548
													计算方法 396*1024/8=50688
(gdb) x/50688a 0x0000555555559000  <----------------------- 查看堆内存地址数据
0x555555559000:	0x0	0x291
...
...
0x55555556aea0:	0x0	0x21
0x55555556aeb0:	0x555555557cd0 <_ZTV7MEMTEST+16>	0xbb114514aa114514
0x55555556aec0:	0x0	0x21
0x55555556aed0:	0x555555557cd0 <_ZTV7MEMTEST+16>	0xbb114514aa114514
0x55555556aee0:	0x0	0x21
0x55555556aef0:	0x555555557cd0 <_ZTV7MEMTEST+16>	0xbb114514aa114514
0x55555556af00:	0x0	0x21
0x55555556af10:	0x555555557cd0 <_ZTV7MEMTEST+16>	0xbb114514aa114514
...

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78

使用 c++filt翻译函数符号名称_ZTV7MEMTEST为MEMTEST虚表指针

root@luo:~/workspace/memtest# c++filt _ZTV7MEMTEST
vtable for MEMTEST
1
2

顺便查看一下虚函数表存的什么,~MEMTEST为虚析构函数地址(c++的多态相关)

(gdb) x/10a 0x555555557cd0
0x555555557cd0 <_ZTV7MEMTEST+16>:	0x555555555330 <MEMTEST::~MEMTEST()>	0x55555555534e <MEMTEST::~MEMTEST()>
1
2

在类中没有虚函数时的内存

0x55555556aea0:	0x0	0x21
0x55555556aeb0:	0xbb114514aa114514	0x0
0x55555556aea0:	0x0	0x21
0x55555556aeb0:	0xbb114514aa114514	0x0
1
2
3
4

在类中有虚函数时的内存

0x55555556aea0:	0x0	0x21
0x55555556aeb0:	0x555555557cd0 <_ZTV7MEMTEST+16>	0xbb114514aa114514
0x55555556aec0:	0x0	0x21
0x55555556aed0:	0x555555557cd0 <_ZTV7MEMTEST+16>	0xbb114514aa114514
0x55555556aee0:	0x0	0x21
0x55555556aef0:	0x555555557cd0 <_ZTV7MEMTEST+16>	0xbb114514aa114514
1
2
3
4
5
6

# 源码memtest.cpp

#include <iostream>
using namespace std;

class MEMTEST
{
public:
    // 注释掉后就没有 虚表指针 0x555555557cd0 <_ZTV7MEMTEST+16>
    virtual ~MEMTEST() {}

    int i;
    int j;
};

void f()
{
    for (int i = 0; i < 10000; ++i)
    {
        //
        MEMTEST *p = new MEMTEST;
        p->i = 0xAA114514;
        p->j = 0xBB114514;
    }

    throw std::bad_alloc();
}

int main()
{
    f();

    return 0;
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33