zoukankan      html  css  js  c++  java
  • C++内存泄露

    C++内存泄露一直是个头痛的问题,但是总要解决吧,在网上搜了很久以后,终于找到了一个不是办法的办法,这个办法有缺陷,但是有总比没有强吧!
    使用的编译器:VS2010。
    这里需要说点汇编的知识:
    void fun(int nVal)
    {
    }
    当调用函数fun(a)时,首先a会入栈,其次是返回地址会入栈,我们可以重载operator new和operator delete来记录每个调用的地址,然后用链表list1记录new得到的内存块,用链表list2记录delete释放的内存块,最后把这两个链表遍历,比较他的的值,值相同的去掉,剩下不同的值则是没有释放的内存。
     
    0x00414BBC   fun(a);
    0x00414BC1   
    调用fun(a)时,a会入栈,然后会把返回地址(0x00414BC1)入栈。他们的内存是相邻的。所以我们可以把返回地址存储起来,我们就可以知道那段代码调用了这个函数。在VS2010中,调试的时候,右键,转到反汇编,定位到0x00414BC1处,就可以看到。
    struct MenInfo
    {
        unsigned int nNewCalAddress;//new函数调用地址。
        unsigned in nDeleteCallAddress;//delete函数调用地址。
        unsigned int nTotalSize;//内存总大小。我们需要额外的内存来存储一些信息,例如调用地址。
        unsigned int nUseSize;//使用大小。
    };
    list<void *> list1,
    list<void *> list2;
    //其实new只有一个参数,但是VS定义了new宏(大概是为了调试方便吧),所以变成了3个参数,
    void *::operator new(unsigned int size, const char *file, int line)
    {
        //参数入栈的顺序是从右到左,即最后入栈的是变量size
        ////函数返回的地址的地址等于最后入栈变量地址(这里是size)-4
        void **funAddr = (void **)(((int)&size) - 4);//函数返回地址的地址
        unsigned int nFunCallAddress = (*(int *)funAddr);//函数的返回地址
        void *pBuf = NULL;
        int nTotalSize = size + sizeof(MemInfo);//我们需要多分配一点内存来存储MenInfo
        try
        {
        pBuf = malloc(nTotalSize);
        }
        catch (...)
        {
        pBuf = NULL;
        return NULL;
        }
        MemInfo *pMemInfo = (MemInfo *)pBuf;
        pMemInfo->nNewCallAddress = nFunCallAddress;
        pMemInfo->nDeleteCallAddress = NULL;
        pMemInfo->nTotalSize = nTotalSize;
        pMemInfo->nUseSize = size;
        void *buffer = ((char *)pBuf + sizeof(MemInfo));
        memset(buffer, 0, size);
       //list1.push_back(buffer);
        return buffer;
    }
    void ::operator delete(void *buf)
    {

      

        void **funAddr = (void **)(((int)&buf) - 4);//返回地址的地址
        unsigned int nFunCallAddress = (*(int *)funAddr);//得到返回地址
        MemInfo *pMemInfo = (MemInfo *)((char *)buf - sizeof(MemInfo));
        pMemInfo->nDeleteCallAddress = nFunCallAddress;

       

        memset(buf, 0, pMemInfo->nUseSize);
       //没有释放内存,我们需要内存块里面的信息(new函数返回地址,delete函数返回地址),所以只能用于调试。
        //list2.push_back(buf);
    }
    最后是要遍历list1和list2进行比较,就知道哪些内存没有释放,而且从内存块里我没可以知道new函数是在哪里调用的,可以快速定位到代码,从而进行查找原因
  • 相关阅读:
    What is a .Net Assembly?
    Reading Assembly attributes in VB.NET
    Debugging With Visual Studio 2005
    The Rules for GetHashCode
    The article discusses a couple of new features introduced for assemblies and versioning in Visual Studio 2005.
    Getting a copy of a DLL in the GAC
    Modeling SingleNeuron Dynamics and Computations: A Balance of Detail and Abstraction
    从数学到密码学(八)
    从数学到密码学(十)
    从数学到密码学(三)
  • 原文地址:https://www.cnblogs.com/dongc/p/5225138.html
Copyright © 2011-2022 走看看