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函數是在哪裏調用的,可以快速定位到代碼,從而進行查找原因
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章