在編程中經(jīng)常涉及到內(nèi)存管理,于是便希望有個內(nèi)存檢測器來幫助我們debug。我們想檢測內(nèi)存泄漏,就必須記錄程序中的內(nèi)存分配和釋放情況,同時我們也希望能記錄內(nèi)存分配代碼所在行號和位置,也就是我們需要重載以下四個全局函數(shù):
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);
下面將描述如何實現(xiàn)一個簡單的內(nèi)存檢測器
1.獲得內(nèi)存分配代碼所在行號和位置
我們需要將缺省的全局new operator替換為帶有文件名和行號的版本,代碼如下:
#define new new(__FILE__, __LINE__ )
2.建立記錄內(nèi)存分配和釋放情況的數(shù)據(jù)結(jié)構(gòu)NewList
NewList中記錄了內(nèi)存分配代碼所在行號、位置、內(nèi)存分配后獲得指針與大小。由于我們想記錄整個程序中內(nèi)存分配和釋放情況,于是應(yīng)實例化一個NewList全局對象NewRecord。
注意:全局對象應(yīng)放在cpp中,如果放在.h中,.h文件又被多個文件include,于是會出現(xiàn)重定義
3.重載new和delete那四個全局函數(shù)
new:(1)分配內(nèi)存,如果失敗了拋出異常 (2)記錄相關(guān)數(shù)據(jù) (3)返回分配所得指針
注意在重載operator new[]時Size為0的情況,這時我們當Size=1;
delete :(1)找到相關(guān)數(shù)據(jù)并刪除 (2)釋放內(nèi)存
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.如何打印出內(nèi)存泄漏的有關(guān)信息
對于打印信息我們會有各種各樣不同的要求,譬如輸出到控制臺,輸出到文件,同時輸出到控制臺跟文件等。每一種情況都實現(xiàn)一個函數(shù)顯然不可行,為了應(yīng)付這種情況,我們可以考慮如下數(shù)據(jù)結(jié)構(gòu):
class Print{
};
class PrintToConsole : public Print{
};
5.如何使用
(1)讓所有代碼都#include "DebugNew.h",如果有的代碼包含而有的代碼不包含,內(nèi)存分配與釋放信息也就記錄不準確了。
(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; //內(nèi)存分配后獲得的指針
15
size_t Size; //內(nèi)存分配的大小
16
char* FileName; //內(nèi)存分配代碼所在文件位置
17
int LineNum; //內(nèi)存分配代碼所在行號
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("存在內(nèi)存泄漏");
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("不存在內(nèi)存泄漏");
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 閱讀(3219)
評論(2) 編輯 收藏 引用 所屬分類:
其他