参考
实验
1,写一个内存泄露的程序mt.c
#include <stdlib.h>
#include <mcheck.h>
int main()
{
mtrace();
int *a;
a = malloc(sizeof(int));
muntrace();
return 0;
}
加上头文件
#include <mcheck.h>
然后在main()函数的开头加上
mtrace();
在main函数返回前加上
muntrace();
2,设置环境变量
MALLOC_TRACE=/home/stevewong/mtrace/mt.log
export MALLOC_TRACE
3,编译和运行程序
gcc mt.c -g mt.o
./mt.o
4,查看内存报告
mtrace mt.o mt.log
可以看到:
Memory not freed:
-----------------
Address Size Caller
0x0000000000d65460 0x4 at /home/stevewong/mtrace/mt.c:7
5,正确的程序mtfree.c
#include <stdlib.h>
#include <mcheck.h>
int main()
{
mtrace();
int *a;
a = malloc(sizeof(int));
if (a == NULL)
return 1;
free(a);
muntrace();
return 0;
}
6,编译,运行,查看内存泄露的情况
No memory leaks.
7,测试一下new的泄露是否能检测出来
#include <stdlib.h>
#include <new>
#include <mcheck.h>
using namespace std;
int main()
{
mtrace();
int *a;
a = new int[10];
muntrace();
return 0;
}
Memory not freed:
-----------------
Address Size Caller
0x000000000125d460 0x28 at 0x7fb584cc82e8
0x28就是40个字节,正好对应10个int。
再来看一个类的例子
include <stdlib.h>
#include <new>
#include <mcheck.h>
#include <iostream>
using namespace std;
class C
{
public:
C()
{
cout << "new " << this << endl;
}
~C()
{
cout << "delete " << this << endl;
}
};
int main()
{
mtrace();
C *pc;
pc = new C[10];
cout << "addr of pc: " << pc << endl;
cout << "size of pc: " << sizeof(pc) << endl;
cout << "size of class C: "<< sizeof(C) << ", " << sizeof(pc[0]) << endl;
//delete []pc;
muntrace();
return 0;
}
输出:
new 0x1eb9468
new 0x1eb9469
new 0x1eb946a
new 0x1eb946b
new 0x1eb946c
new 0x1eb946d
new 0x1eb946e
new 0x1eb946f
new 0x1eb9470
new 0x1eb9471
addr of pc: 0x1eb9468
size of pc: 8
size of class C: 1, 1
内存泄露检测
Memory not freed:
-----------------
Address Size Caller
0x0000000001eb9460 0x12 at 0x7fefd2c802e8
一个只有构造函数和析构函数的类占1个字节(构造函数和析构函数不占空间),10个空类10个字节,但是内存泄露检测显示size是0x12也就是18个字节,多出来的8个字节是?
使用gdb查看内存可以发现
display *((int*)0x1eb9460)
结果是10。说明这8个字节是存了数组的长度。
可以参考以下文章:
C++对象模型之简述C++对象的内存布局
如果只是delete了pc,没有delete整个对象数组呢?
#include <stdlib.h>
#include <new>
#include <mcheck.h>
#include <iostream>
using namespace std;
class C
{
public:
C()
{
cout << "new " << this << endl;
}
~C()
{
cout << "delete " << this << endl;
}
};
int main()
{
mtrace();
C *pc;
pc = new C[4];
cout << "addr of pc: " << pc << endl;
cout << "size of pc: " << sizeof(pc) << endl;
cout << "size of class C: "<< sizeof(C) << ", " << sizeof(pc[0]) << endl;
delete pc;
muntrace();
return 0;
}
只调用了一个析构函数,然后就出错了。
new 0x13d3468
new 0x13d3469
new 0x13d346a
new 0x13d346b
new 0x13d346c
new 0x13d346d
new 0x13d346e
new 0x13d346f
new 0x13d3470
new 0x13d3471
addr of pc: 0x13d3468
size of pc: 8
size of class C: 1, 1
delete 0x13d3468
*** Error in `./new': munmap_chunk(): invalid pointer: 0x00000000013d3468 ***
Aborted
查看内存泄露文件mt.log
- 0x00000000013d3468 Free 3 was never alloc'd /home/stevewong/mtrace/new.c:29
Memory not freed:
-----------------
Address Size Caller
0x00000000013d3460 0x12 at 0x7f0ab50e52e8
泄露的长度是0x12=18,也就说所有的内存都没被释放。
这里有个有趣的问题,如果把数组长度设置为4的话,并没有内存泄露,而是出现了segmentation fault。求高手指教一下这是为什么。
对应的输出是
new 0x1f7a468
new 0x1f7a469
new 0x1f7a46a
new 0x1f7a46b
addr of pc: 0x1f7a468
size of pc: 8
size of class C: 1, 1
delete 0x1f7a468
Segmentation fault
对应的内存泄露文件是
No memory leaks.
8,还是把new的例子写好看看情况
#include <stdlib.h>
#include <new>
#include <mcheck.h>
#include <iostream>
using namespace std;
class C
{
public:
C()
{
cout << "new " << this << endl;
}
~C()
{
cout << "delete " << this << endl;
}
};
int main()
{
mtrace();
C *pc;
pc = new C[10];
delete []pc;
muntrace();
return 0;
}
输出:
new 0x108c468
new 0x108c469
new 0x108c46a
new 0x108c46b
new 0x108c46c
new 0x108c46d
new 0x108c46e
new 0x108c46f
new 0x108c470
new 0x108c471
delete 0x108c471
delete 0x108c470
delete 0x108c46f
delete 0x108c46e
delete 0x108c46d
delete 0x108c46c
delete 0x108c46b
delete 0x108c46a
delete 0x108c469
delete 0x108c468
内存泄露查看:No memory leaks.

本文介绍如何使用mtrace工具进行C/C++程序的内存泄漏检测,包括创建内存泄漏示例程序、设置环境变量、编译运行及分析内存报告等步骤。同时通过具体案例对比正确与错误的内存管理方式。

2907

被折叠的 条评论
为什么被折叠?



