在编程中经常涉及到内存管理,于是便希望有个内存检测器来帮助我们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)
![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif)
{
if (Size==(size_t)0) Size=1;
void* Result=::operator new(Size);
if (!Result) throw bad_alloc();
else
![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
NewListNode Temp(Result, Size, FileName, LineNum);
NewRecord.Add(Temp);
return Result;
}
}
![](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
void* operator new[](size_t Size, char* FileName, int LineNum)
![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif)
{
if (Size==(size_t)0) Size=1;
void* Result=::operator new[](Size);
if (!Result) throw bad_alloc();
else
![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
NewListNode Temp(Result, Size, FileName, LineNum);
NewRecord.Add(Temp);
return Result;
}
}
![](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
void operator delete(void* Object)
![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif)
{
if (!Object) return;
NewRecord.Remove(Object);
free(Object);
}
![](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
void operator delete[](void* Object)
![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif)
{
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;
}
![](http://www.cppblog.com/images/cppblog_com/lyt/Temp.jpg)
#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;
}
![](http://www.cppblog.com/images/cppblog_com/lyt/Temp.jpg.jpg)
DebugNew.h
1
#ifndef DEBUGNEW_H
2
#define DEBUGNEW_H
3![](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
4
#include <iostream>
5
#include <stdlib.h>
6
#include "Link.h"
7
#include "Print.h"
8![](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
9
using namespace std;
10![](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
11
class NewListNode
12![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif)
{
13
public:
14
void* Object; //内存分配后获得的指针
15
size_t Size; //内存分配的大小
16
char* FileName; //内存分配代码所在文件位置
17
int LineNum; //内存分配代码所在行号
18![](http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif)
19
NewListNode();
20
NewListNode(void* Buffer, size_t s, char* File, int Line);
21
NewListNode(const NewListNode& Temp);
22
};
23![](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
24
class NewList
25![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif)
{
26
public:
27
Link<NewListNode> Data;
28![](http://www.cppblog.com/Images/OutliningIndicators/InBlock.gif)
29
bool IsEmpty();
30
void Add(const NewListNode& Temp);
31
void Remove(void* Object);
32
void Check();
33
};
34![](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
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![](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
40
extern void Check();
41
extern NewList NewRecord;
42![](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
43
#define new new(__FILE__, __LINE__ )
44
#endif
DebugNew.cpp
1
#include "DebugNew.h"
2
#undef new
3![](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
4
NewListNode::NewListNode()
5![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif)
{
6
Object=0;
7
FileName=0;
8
}
9![](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
10
NewListNode::NewListNode(void* Buffer, size_t s, char* File, int Line)
11![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif)
{
12
Object=Buffer;
13
Size=s;
14
FileName=File;
15
LineNum=Line;
16
}
17![](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
18
NewListNode::NewListNode(const NewListNode& Temp)
19![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif)
{
20
FileName=Temp.FileName;
21
LineNum=Temp.LineNum;
22
Object=Temp.Object;
23
Size=Temp.Size;
24
}
25![](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
26
bool NewList::IsEmpty()
27![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif)
{
28
if (Data.GetHead()) return false;
29
else return true;
30
}
31![](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
32
void NewList::Add(const NewListNode& Temp)
33![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif)
{
34
Data.AddLast()->Data=Temp;
35
}
36![](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
37
void NewList::Remove(void* Object)
38![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif)
{
39
Node<NewListNode>* Temp=Data.GetHead();
40
while (Temp)
41![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
42
if (Temp->Data.Object==Object)
43![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
44
Data.Delete(Temp);
45
return;
46
}
47
Temp=Temp->Next;
48
}
49
}
50![](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
51
void NewList::Check()
52![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif)
{
53
PrintToConsole Printer;
54
if (!IsEmpty())
55![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
56
Printer.Writeln("存在内存泄漏");
57
Printer.Writeln("Line\tSize\tPath");
58
Printer.WriteLine();
59
Node<NewListNode>* Temp=Data.GetHead();
60
while (Temp)
61![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
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![](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
78
NewList NewRecord;
79![](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
80
void* operator new(size_t Size, char* FileName, int LineNum)
81![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif)
{
82
if (Size==(size_t)0) Size=1;
83
void* Result=::operator new(Size);
84
if (!Result) throw bad_alloc();
85
else
86![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
87
NewListNode Temp(Result, Size, FileName, LineNum);
88
NewRecord.Add(Temp);
89
return Result;
90
}
91
}
92![](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
93
void* operator new[](size_t Size, char* FileName, int LineNum)
94![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif)
{
95
if (Size==(size_t)0) Size=1;
96
void* Result=::operator new[](Size);
97
if (!Result) throw bad_alloc();
98
else
99![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedSubBlockStart.gif)
{
100
NewListNode Temp(Result, Size, FileName, LineNum);
101
NewRecord.Add(Temp);
102
return Result;
103
}
104
}
105![](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
106
void operator delete(void* Object)
107![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif)
{
108
if (!Object) return;
109
NewRecord.Remove(Object);
110
free(Object);
111
}
112![](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
113
void operator delete[](void* Object)
114![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif)
{
115
if (!Object) return;
116
NewRecord.Remove(Object);
117
free(Object);
118
}
119![](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
120
void Check()
121![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif)
{
122
NewRecord.Check();
123
}
Print.h
1
#ifndef PRINT_H
2
#define PRINT_H
3![](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
4
#include <stdlib.h>
5
#include <iostream>
6![](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
7
using namespace std;
8![](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
9
class Print
10![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif)
{
11
public:
12
virtual ~Print();
13
};
14![](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
15
class PrintToConsole : public Print
16![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif)
{
17
public:
18
virtual ~PrintToConsole();
19
virtual void Write(char* String);
20
virtual void Writeln(char* String);
21
virtual void WriteLine();
22
};
23![](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
24
#endif
Print.cpp
1
#include "Print.h"
2![](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
3
Print:: ~Print()
4![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif)
{
5
}
6![](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
7
PrintToConsole::~PrintToConsole()
8![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif)
{
9
}
10![](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
11
void PrintToConsole::Write(char* String)
12![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif)
{
13
if (String) cout<<String;
14
}
15![](http://www.cppblog.com/Images/OutliningIndicators/None.gif)
16
void PrintToConsole::Writeln(char* String)
17![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif)
{
18
if (String) cout<<String<<endl;
19
else cout<<endl;
20
}
21
22
void PrintToConsole::WriteLine()
23![](http://www.cppblog.com/Images/OutliningIndicators/ExpandedBlockStart.gif)
![](http://www.cppblog.com/Images/OutliningIndicators/ContractedBlock.gif)
{
24
cout<<"-------------------------------------------------------------------------------"<<endl;
25
}
posted on 2009-03-25 01:56
Lyt 阅读(3200)
评论(2) 编辑 收藏 引用 所属分类:
其他