您的位置:首页 > 其它

内存泄漏及检测

2016-07-14 17:39 197 查看
一、What?

内存泄漏:由于程序员的疏忽或错误造成程序未能释放已不在使用的内存,导致减少可用内存,降低计算机性能,导致程序崩溃。

内存溢出:是指已有的数据超过了其获得到的内存所能存储的范围,比如用一个字节存放1000这个数字就属于内存溢出。

int *p = new int;
return 0;


new之后没有delete,那么return后就会发生内存泄露。

虽然看上去这样并不造成什么严重后果,但是

while(true)
{
int *p = new int;
}
return 0;


这种也是人为错误,甚至会导致程序崩溃。

而在代码量很大的情况下并不好检查,所以需要使用工具来进行内存泄漏的检测,辅助我们找到内存泄漏代码的地方:某某文件、某某行。

二、How?

一种简单的检测方法:

1、原理:

C++有操作符重载的机制,所以可以通过重载 new、delete 操作符,来做一些处理。

每次执行 new 操作时,将指针和当前文件名称和行号保存在我们自己维护的一个容器里;执行 delete 时,将对应指针的项从容器中删除,最后程序结束时检查容器中是否还有未释放的指针。



2、实现:

(1)new操作符重载

#define new new(__FILE__,__LINE__)

void* operator new(size_t size, const char* file, long line)
{
void* p = malloc(size);
mch.Add(p, file, line);  //往容器中添加项
return p;
}


(2)delete操作符重载

void operator delete(void* p)
{
mch.Remove(p); //删除容器中对应指针
free(p);
}


测试之后出现两个Bug

测试1::



new之后未释放结果检测内存泄漏了

测试2:



new 之后明明 delete 了,为什么还会出现内存泄漏呢?

原因是 new 了数组后执行的是 delete[] ,而重载的是 delete,所以容器里面指针的并没有删除,那么就需要重载 delete[]

void operator delete[](void* p)
{
mch.Remove(p);
free(p);
}


测试3:



在前面两个测试中也出现了这样的异常崩溃。

首先,程序在加载时:

a、将程序加载到系统内存;

b、将原有 new 和 delete 全部替换;

c、程序需要执行 new 和 delete 的地方都被监管;

最后,程序卸载:

a、将程序中的对象析构;

b、对象被析构之后以及不存在;

c、此时 delete 和 new 里面还在使用这个对象,所以造成异常崩溃。

所以在类中添加一个 static bool Ready;构造函数初始化它为 true,析构函数让它为 false,在对象存在的时候才可以 new 和 delete。

#include "MemChecker.h"

MemChecker mch;
bool MemChecker::Ready = false;

void* operator new(size_t size, const char* file, long line)
{
void* p = malloc(size);
if (MemChecker::Ready)
mch.Add(p, file, line);
return p;
}
void operator delete(void* p)
{
if (MemChecker::Ready)
mch.Remove(p);
free(p);
}
void operator delete[](void* p)
{
if (MemChecker::Ready)
mch.Remove(p);
free(p);
}

MemChecker::MemChecker()
{
Ready = true;
}
MemChecker::~MemChecker()
{
Dump();
Ready = false;
}
void MemChecker::Add(void* pointer, const char* file, long line)
{
pointer_map_[pointer] = Entry(file, line);
}
void MemChecker::Remove(void* pointer)
{
auto iter = pointer_map_.find(pointer);
if (iter != pointer_map_.end())
{
pointer_map_.erase(iter);
}
}
void MemChecker::Dump()
{
if (!pointer_map_.empty())
{
cout << "内存泄露" << endl;
for (auto iter = pointer_map_.begin(); iter != pointer_map_.end(); ++iter)
{
const char* file = iter->second.File();
long line = iter->second.Line();
cout << "在" << file << "\t" << line << "出现内存泄露" << endl;
}
}
}


代码地址:https://github.com/xyr129/MemChecker
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  内存泄露