在编程中经常涉及到内存管理,于是便希望有个内存检测器来帮助我们debug。我们想检测内存泄漏,就必须记录程序中的内存分配和释放情况,同时我们也希望能记录内存分配代码所在行号和位置,也就是我们需要重载以下四个全局函数:
void* operator new(size_t Size, char* FileName, int LineNum);
void* operator new[](size_t Size, char* FileName, int LineNum);
void operator delete(void* Object);
void operator delete[](void* Object);
下面将描述如何实现一个简单的内存检测器
1.获得内存分配代码所在行号和位置
我们需要将缺省的全局new operator替换为带有文件名和行号的版本,代码如下:
#define new new(__FILE__, __LINE__ )
2.建立记录内存分配和释放情况的数据结构NewList
NewList中记录了内存分配代码所在行号、位置、内存分配后获得指针与大小。由于我们想记录整个程序中内存分配和释放情况,于是应实例化一个NewList全局对象NewRecord。
注意:全局对象应放在cpp中,如果放在.h中,.h文件又被多个文件include,于是会出现重定义
3.重载new和delete那四个全局函数
new:(1)分配内存,如果失败了抛出异常 (2)记录相关数据 (3)返回分配所得指针
注意在重载operator new[]时Size为0的情况,这时我们当Size=1;
delete :(1)找到相关数据并删除 (2)释放内存
void* operator new(size_t Size, char* FileName, int LineNum)


{
if (Size==(size_t)0) Size=1;
void* Result=::operator new(Size);
if (!Result) throw bad_alloc();
else

{
NewListNode Temp(Result, Size, FileName, LineNum);
NewRecord.Add(Temp);
return Result;
}
}

void* operator new[](size_t Size, char* FileName, int LineNum)


{
if (Size==(size_t)0) Size=1;
void* Result=::operator new[](Size);
if (!Result) throw bad_alloc();
else

{
NewListNode Temp(Result, Size, FileName, LineNum);
NewRecord.Add(Temp);
return Result;
}
}

void operator delete(void* Object)


{
if (!Object) return;
NewRecord.Remove(Object);
free(Object);
}

void operator delete[](void* Object)


{
if (!Object) return;
NewRecord.Remove(Object);
free(Object);
}
4.如何打印出内存泄漏的有关信息
对于打印信息我们会有各种各样不同的要求,譬如输出到控制台,输出到文件,同时输出到控制台跟文件等。每一种情况都实现一个函数显然不可行,为了应付这种情况,我们可以考虑如下数据结构:
class Print{
};
class PrintToConsole : public Print{
};
5.如何使用
(1)让所有代码都#include "DebugNew.h",如果有的代码包含而有的代码不包含,内存分配与释放信息也就记录不准确了。
(2)此代码无法处理多线程的情况
6.使用效果
#include "DebugNew.h"
#include <stdlib.h>
#include <iostream>
#include <conio.h>
using namespace std;
int main(int argc , char* argv[])
{
new int;
Check();
_getch();
return 0;
}

#include "DebugNew.h"
#include <stdlib.h>
#include <iostream>
#include <conio.h>
using namespace std;
int main(int argc , char* argv[])
{
int* p=new int;
delete p;
Check();
_getch();
return 0;
}

DebugNew.h
1
#ifndef DEBUGNEW_H
2
#define DEBUGNEW_H
3
4
#include <iostream>
5
#include <stdlib.h>
6
#include "Link.h"
7
#include "Print.h"
8
9
using namespace std;
10
11
class NewListNode
12

{
13
public:
14
void* Object; //内存分配后获得的指针
15
size_t Size; //内存分配的大小
16
char* FileName; //内存分配代码所在文件位置
17
int LineNum; //内存分配代码所在行号
18
19
NewListNode();
20
NewListNode(void* Buffer, size_t s, char* File, int Line);
21
NewListNode(const NewListNode& Temp);
22
};
23
24
class NewList
25

{
26
public:
27
Link<NewListNode> Data;
28
29
bool IsEmpty();
30
void Add(const NewListNode& Temp);
31
void Remove(void* Object);
32
void Check();
33
};
34
35
extern void* operator new(size_t Size, char* FileName, int LineNum);
36
extern void* operator new[](size_t Size, char* FileName, int LineNum);
37
extern void operator delete(void* Object);
38
extern void operator delete[](void* Object);
39
40
extern void Check();
41
extern NewList NewRecord;
42
43
#define new new(__FILE__, __LINE__ )
44
#endif
DebugNew.cpp
1
#include "DebugNew.h"
2
#undef new
3
4
NewListNode::NewListNode()
5

{
6
Object=0;
7
FileName=0;
8
}
9
10
NewListNode::NewListNode(void* Buffer, size_t s, char* File, int Line)
11

{
12
Object=Buffer;
13
Size=s;
14
FileName=File;
15
LineNum=Line;
16
}
17
18
NewListNode::NewListNode(const NewListNode& Temp)
19

{
20
FileName=Temp.FileName;
21
LineNum=Temp.LineNum;
22
Object=Temp.Object;
23
Size=Temp.Size;
24
}
25
26
bool NewList::IsEmpty()
27

{
28
if (Data.GetHead()) return false;
29
else return true;
30
}
31
32
void NewList::Add(const NewListNode& Temp)
33

{
34
Data.AddLast()->Data=Temp;
35
}
36
37
void NewList::Remove(void* Object)
38

{
39
Node<NewListNode>* Temp=Data.GetHead();
40
while (Temp)
41
{
42
if (Temp->Data.Object==Object)
43
{
44
Data.Delete(Temp);
45
return;
46
}
47
Temp=Temp->Next;
48
}
49
}
50
51
void NewList::Check()
52

{
53
PrintToConsole Printer;
54
if (!IsEmpty())
55
{
56
Printer.Writeln("存在内存泄漏");
57
Printer.Writeln("Line\tSize\tPath");
58
Printer.WriteLine();
59
Node<NewListNode>* Temp=Data.GetHead();
60
while (Temp)
61
{
62
char Line[20];
63
itoa(Temp->Data.LineNum, Line, 10);
64
Printer.Write(Line);
65
Printer.Write("\t");
66
char s[200];
67
itoa(Temp->Data.Size, s, 10);
68
Printer.Write(s);
69
Printer.Write("\t");
70
Printer.Write(Temp->Data.FileName);
71
Printer.Write("\t");
72
Temp=Temp->Next;
73
}
74
}
75
else Printer.Writeln("不存在内存泄漏");
76
}
77
78
NewList NewRecord;
79
80
void* operator new(size_t Size, char* FileName, int LineNum)
81

{
82
if (Size==(size_t)0) Size=1;
83
void* Result=::operator new(Size);
84
if (!Result) throw bad_alloc();
85
else
86
{
87
NewListNode Temp(Result, Size, FileName, LineNum);
88
NewRecord.Add(Temp);
89
return Result;
90
}
91
}
92
93
void* operator new[](size_t Size, char* FileName, int LineNum)
94

{
95
if (Size==(size_t)0) Size=1;
96
void* Result=::operator new[](Size);
97
if (!Result) throw bad_alloc();
98
else
99
{
100
NewListNode Temp(Result, Size, FileName, LineNum);
101
NewRecord.Add(Temp);
102
return Result;
103
}
104
}
105
106
void operator delete(void* Object)
107

{
108
if (!Object) return;
109
NewRecord.Remove(Object);
110
free(Object);
111
}
112
113
void operator delete[](void* Object)
114

{
115
if (!Object) return;
116
NewRecord.Remove(Object);
117
free(Object);
118
}
119
120
void Check()
121

{
122
NewRecord.Check();
123
}
Print.h
1
#ifndef PRINT_H
2
#define PRINT_H
3
4
#include <stdlib.h>
5
#include <iostream>
6
7
using namespace std;
8
9
class Print
10

{
11
public:
12
virtual ~Print();
13
};
14
15
class PrintToConsole : public Print
16

{
17
public:
18
virtual ~PrintToConsole();
19
virtual void Write(char* String);
20
virtual void Writeln(char* String);
21
virtual void WriteLine();
22
};
23
24
#endif
Print.cpp
1
#include "Print.h"
2
3
Print:: ~Print()
4

{
5
}
6
7
PrintToConsole::~PrintToConsole()
8

{
9
}
10
11
void PrintToConsole::Write(char* String)
12

{
13
if (String) cout<<String;
14
}
15
16
void PrintToConsole::Writeln(char* String)
17

{
18
if (String) cout<<String<<endl;
19
else cout<<endl;
20
}
21
22
void PrintToConsole::WriteLine()
23

{
24
cout<<"-------------------------------------------------------------------------------"<<endl;
25
}
posted on 2009-03-25 01:56
Lyt 阅读(3214)
评论(2) 编辑 收藏 引用 所属分类:
其他