C++內存洩露及檢測對象詳解。本站提示廣大學習愛好者:(C++內存洩露及檢測對象詳解)文章只能為提供參考,不一定能成為您想要的結果。以下是C++內存洩露及檢測對象詳解正文
起首我們須要曉得法式有無內存洩漏,然後定位究竟是哪行代碼湧現內存洩漏了,如許能力將其修復。
最簡略的辦法固然是借助於專業的檢測對象,比擬著名如BoundsCheck,功效異常壯大,信任做C++開辟的人都離不開它。另外就是不應用任何對象,而是本身來完成對內存洩漏的監控,分以下兩種情形:
一. 在 MFC 中檢測內存洩露
假設是用MFC的法式的話,很簡略。默許的就有內存洩漏檢測的功效。
我們用VS2005生成了一個MFC的對話框的法式,發明他可以主動的檢測內存洩漏.不消我們做任何特別的操作. 細心不雅察,發明在每一個CPP文件中,都有上面的代碼:
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
DEBUG_NEW 這個宏界說在afx.h文件中,就是它贊助我們定位內存洩露。
在含有以上代碼的cpp文件平分配內存後假設沒有刪除,那末停滯法式的時刻,VisualStudio的Output窗口就會顯示以下的信息了:
Detected memory leaks!
Dumping objects ->
d:\code\mfctest\mfctest.cpp(80) : {157} normal block at 0x003AF170, 4 bytes long.
Data: < > 00 00 00 00
Object dump complete.
在Output窗口雙擊粗體字那一行,那末IDE就會翻開該文件,定位到該行,很輕易看出是哪湧現了內存洩漏。
二.檢測純C++的法式內存洩漏
我試了下用VisualStudio樹立的Win32 Console Application和Win32 Project項目,成果都不克不及檢測出內存洩漏。
上面一步一步來把法式的內存洩漏檢測的機制樹立起來。
起首,我們須要曉得C運轉庫的Debug版本供給了很多檢測功效,使得我們更輕易的Debug法式。在MSDN中有專門的章節講這個,叫做Debug Routines,建議年夜家先看看外面的內容吧。
我們會用到外面很主要的幾個函數。個中最主要的是 _CrtDumpMemoryLeaks();本身看MSDN裡的贊助吧。應用這個函數,須要包括頭文件crtdbg.h
該函數只在Debug版本才有效,當在調試器下運轉法式時,_CrtDumpMemoryLeaks 將在“Output(輸入)”窗口中顯示內存洩露信息.寫段代碼實驗一下吧,以下:
檢測內存洩漏版本一:
#include "stdafx.h"
#include <crtdbg.h>
int _tmain(int argc, _TCHAR* argv[])
{
int* p = new int();
_CrtDumpMemoryLeaks();
return 0;
}
運轉後,在Output(輸入)窗口,顯示了以下的信息:
Detected memory leaks!
Dumping objects ->
{112} normal block at 0x003AA770, 4 bytes long.
Data: < > 00 00 00 00
Object dump complete.
然則這個只是告知我們法式有內存洩漏,究竟在哪洩漏了一眼看不出來啊。
看我們的檢測內存洩漏版本二:
#include "stdafx.h"
#ifdef _DEBUG
#define DEBUG_CLIENTBLOCK new( _CLIENT_BLOCK, __FILE__, __LINE__)
#else
#define DEBUG_CLIENTBLOCK
#endif
#define _CRTDBG_MAP_ALLOC
#include <crtdbg.h>
#ifdef _DEBUG
#define new DEBUG_CLIENTBLOCK
#endif
int _tmain(int argc, _TCHAR* argv[])
{
int* p = new int();
_CrtDumpMemoryLeaks();
return 0;
}
該法式界說了幾個宏,經由過程宏將Debug版本下的new給調換了,新的new記載下了挪用new時的文件名和代碼行.運轉後,可以看到以下的成果:
Detected memory leaks!
Dumping objects ->
d:\code\consoletest\consoletest.cpp(21) : {112} client block at 0x003A38B0, subtype 0, 4 bytes long.
Data: < > 00 00 00 00
Object dump complete.
呵呵,曾經和MFC法式的後果一樣了,然則等一等。看下以下的代碼吧:
int _tmain(int argc, _TCHAR* argv[])
{
int* p = new int();
_CrtDumpMemoryLeaks();
delete p;
return 0;
}
運轉後可以發明我們刪除指針,然則它依然報內存洩漏。所以可以想象,每挪用一次new,法式外部都邑將該挪用記載上去,相似於有個數組記載,假設delete了,那末就將其從數組中刪除,而_CrtDumpMemoryLeaks()就是把這個數組以後的狀況打印出來。
所以除在需要的時刻Dump出內存信息外,最主要的就是在法式加入的時刻須要失落用一次_CrtDumpMemoryLeaks();
假設法式有不止一個出口,那末我們就須要在多個處所都挪用該函數。
更進一步,假設法式在類的析構函數裡刪除指針,怎樣辦?例如:
#include "stdafx.h"
#ifdef _DEBUG
#define DEBUG_CLIENTBLOCK new( _CLIENT_BLOCK, __FILE__, __LINE__)
#else
#define DEBUG_CLIENTBLOCK
#endif
#define _CRTDBG_MAP_ALLOC
#include <crtdbg.h>
#ifdef _DEBUG
#define new DEBUG_CLIENTBLOCK
#endif
class Test
{
public:
Test() { _p = new int(); }
~Test() { delete _p; }
int* _p;
};
int _tmain(int argc, _TCHAR* argv[])
{
int* p = new int();
delete p;
Test t;
_CrtDumpMemoryLeaks();
return 0;
}
可以看到析構函數在法式加入的時刻才挪用,明明沒有內存洩漏,然則如許的寫法照樣報了。
若何改良呢,看檢測內存洩漏版本三:
#include "stdafx.h"
#ifdef _DEBUG
#define DEBUG_CLIENTBLOCK new( _CLIENT_BLOCK, __FILE__, __LINE__)
#else
#define DEBUG_CLIENTBLOCK
#endif
#define _CRTDBG_MAP_ALLOC
#include <crtdbg.h>
#ifdef _DEBUG
#define new DEBUG_CLIENTBLOCK
#endif
class Test
{
public:
Test() { _p = new int(); }
~Test() { delete _p; }
int* _p;
};
int _tmain(int argc, _TCHAR* argv[])
{
_CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );
int* p = new int();
delete p;
Test t;
return 0;
}
_CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );該語句在法式加入時主動挪用 _CrtDumpMemoryLeaks。必需同時設置 _CRTDBG_ALLOC_MEM_DF 和 _CRTDBG_LEAK_CHECK_DF.
如許,該版本曾經到達了MFC一樣的後果了,然則我認為光如許還不敷,由於我們只是在Output窗口中輸入信息,對開辟人員的提示還不顯著,常常會被漏掉,並且許多人就算發明了內存洩漏,然則欠好修復,不會嚴重影響到法式內在表示,都不會修復。怎樣樣能閃開發人員自動的修復內存洩漏的成績呢?記得已經和人合營寫法式,我的函數參數有請求,不克不及為空,然則他人總是傳空值,沒方法了,只好在函數開端驗證函數參數,給他assert住,如許法式運轉時總是一直的彈出assert,調試法式誰人煩壓,最初其他法式員煩了,就把這個成績給改好了,輸出參數就准確了。所以我認為咱要讓法式員自動去做一件事,起首要讓他認為做這個事是能加重本身累贅,讓本身任務輕松的。呵呵,那我們也如許,當法式加入時,檢測到內存洩漏就讓法式提醒出來。
看檢測內存洩漏版本四:
#include "stdafx.h"
#include <assert.h>
#ifdef _DEBUG
#define DEBUG_CLIENTBLOCK new( _CLIENT_BLOCK, __FILE__, __LINE__)
#else
#define DEBUG_CLIENTBLOCK
#endif
#define _CRTDBG_MAP_ALLOC
#include <crtdbg.h>
#ifdef _DEBUG
#define new DEBUG_CLIENTBLOCK
#endif
void Exit()
{
int i = _CrtDumpMemoryLeaks();
assert( i == 0);
}
int _tmain(int argc, _TCHAR* argv[])
{
atexit(Exit);
int* p = new int();
return 0;
}
該版本會在法式加入時檢討內存洩漏,假設存在就會彈出提醒對話框.
atexit(Exit);設置了在法式加入時履行Exit()函數。Exit()函數中,假設存在內存洩漏,_CrtDumpMemoryLeaks()會前往非0值,就會被assert住了。
到這個版本曾經到達可使用的水平了。然則我們還可以做些改良,由於真要精確的檢測到代碼中一切的內存洩漏,須要把代碼中的#define……拷貝到一切應用new的文件中。弗成能每一個文件都拷貝這麼多代碼,所以我們可以將他提掏出來,放在一個文件中,好比我是放在KDetectMemoryLeak.h中,該文件內容以下:
#pragma once
#ifdef _DEBUG
#define DEBUG_CLIENTBLOCK new( _CLIENT_BLOCK, __FILE__, __LINE__)
#else
#define DEBUG_CLIENTBLOCK
#endif
#define _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>
#ifdef _DEBUG
#define new DEBUG_CLIENTBLOCK
#endif
然後將KDetectMemoryLeak.h包括在項目標通用文件中,例如用VS建的項目就將其包括在stdafx.h中。或許我本身建的一個Common.h文件中,該文件包括一些通用的,根本一切文件都邑用到的代碼。