内存泄漏及检测

一、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

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值