内存泄漏专题(8)hook之C++运算符重载

C++主要是针对new/delete运算符进行重载 ,思路和上述hook malloc函数一样,我们可以定义一个MemCheck类,该类用来存储内存信息,包括内存的地址,大小。如果愿意的话,还可以存储调用的位置,这里为了简化处理,就不演示了。在调用 new运算符时,我们将申请内存的相关信息存入MemCheck中的一个map中,它的key是内存地址,value是内存大小。在调用delete时,将该内存地址从map中删除掉。(此处未判断double free的问题,可以考虑下如何去做?)有兴趣的话也可以考虑一下new[]delete[]的重载实现。

我们定义一个全局静态的MemCheck类实例,这样该实例对象的析构将会在main函数结束后才会进行,因此,我们只需要在析构函数中判断一下,map中是否还有没有元素存在,就知道还有没有内存泄漏了。将其打印出来即可。

完整代码示例如下:

//new.cpp
#include <iostream>
#include <malloc.h>
#include <memory>
#include <map>

bool new_enabled = true;

class MemCheck
{
private:
    std::map<void*, size_t> MemInfo; //key 为申请内存的地址, value为申请内存的大小
public:
    void Allocation(void *p, size_t size){
        //申请内存时将内存信息放入map
        new_enabled = false;
        MemInfo[p] = size;
        new_enabled = true;
    }

    void Freed(void *p) {
        //释放内存时将内存信息从map中移除
        MemInfo.erase(p);
    }

    ~ MemCheck(){
        std::cout << "Memory Not Freed:\n";
        std::map<void *, size_t>::iterator it = MemInfo.begin();
        while (it != MemInfo.end()) {
            std::cout << "\t[" << it->first << "] " << it->second << " bytes\n";
            it++;
        }
    }
};

static MemCheck mcheck;

void *operator new(size_t size)
{
    if (new_enabled) {
        void *p = malloc(size);
        mcheck.Allocation(p, size);
        return p;
    } else {
        return malloc(size);
    }
}

void operator delete(void *p) {
    mcheck.Freed(p);
    free(p);
}

struct Object {
    int x, y, z;
};

void test(){
    std::string str = "hello";
    Object *obj = new Object;
    std::unique_ptr<Object> obj2(new Object());
    //delete obj;
}

int main(void){
    test();
    int *pInt = new int;
    std::unique_ptr<int> p(new int);
    return 0;
}

以上代码,在test函数中,首先string的内存管理是交由编译器处理的,虽然程序员无需手动管理,但实际上也调用了newdeleteobj对象只有申请,没有释放,obj2是智能指针,其内存的生命周期由编译器进行管理,无需手动释放,在test函数结束时会自动释放掉。

main函数中,pInt的内存只有申请,没有释放,p是智能指针,在main函数结束时会自动释放。因此,该段代码有两处内存泄漏,分别为指针pIntobj,我们运行该段代码:

[root@ck08 memleak]# g++ new.cpp -std=c++11 -g
[root@ck08 memleak]# ./a.out 
Memory Not Freed:
        [0x7c5080] 12 bytes
        [0x7c50e0] 4 bytes

可以看到,确实打印出了两处内存泄漏,第一处是0x7c5080,该地址是obj的地址,第二处是0x7c50e0,正是pInt的地址。而指针p即使是在main函数结束时才被释放,但MemCheck仍然能够感知到其内存被释放了。


本专栏知识点是通过<零声教育>的系统学习,进行梳理总结写下文章,对C/C++课程感兴趣的读者,可以点击链接,查看详细的服务:C/C++Linux服务器开发/高级架构师

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值