国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > C++ > 正文

C++對(duì)Crt內(nèi)存泄漏檢測(cè)的分析

2020-02-24 14:35:35
字體:
供稿:網(wǎng)友

C++對(duì)Crt內(nèi)存泄漏檢測(cè)的分析,盡管這個(gè)概念已經(jīng)讓人說爛了 ,小編在這里還是想簡(jiǎn)單記錄一下, 以備以后查詢。


#ifdef _DEBUG
#define DEBUG_CLIENTBLOCK?? new( _CLIENT_BLOCK, __FILE__, __LINE__)
#else
#define DEBUG_CLIENTBLOCK
#endif
#define _CRTDBG_MAP_ALLOC
#include
#ifdef _DEBUG
#define new DEBUG_CLIENTBLOCK
#endif

?


int _tmain(int argc, _TCHAR* argv[])
{
??? char* p = new char();
??? char* pp = new char[10];
??? char* ppp = (char*)malloc(10);

??? _CrtDumpMemoryLeaks();

??? return 0;
}


主要原理是運(yùn)用Crt 的內(nèi)存調(diào)試功能, 通過宏替代默認(rèn)的operator new, 讓它被下面版本替代:

?

?


void *__CRTDECL operator new(
??????? size_t cb,
??????? int nBlockUse,
??????? const char * szFileName,
??????? int nLine
??????? )
??????? _THROW1(_STD bad_alloc)
{
??? /* _nh_malloc_dbg already calls _heap_alloc_dbg in a loop and calls _callnewh
?????? if the allocation fails. If _callnewh returns (very likely because no
?????? new handlers have been installed by the user), _nh_malloc_dbg returns NULL.
???? */
??? void *res = _nh_malloc_dbg( cb, 1, nBlockUse, szFileName, nLine );

?

??? RTCCALLBACK(_RTC_Allocate_hook, (res, cb, 0));

??? /* if the allocation fails, we throw std::bad_alloc */
??? if (res == 0)
??? {
??????? static const std::bad_alloc nomem;
??????? _RAISE(nomem);
??? }

??? return res;
}


這樣Crt會(huì)把此次分配內(nèi)存的文件名和行號(hào)以及大小等記錄下來,最后當(dāng)調(diào)用用_CrtDumpMemoryLeaks(); 時(shí)如果還沒釋放就會(huì)打印出來。
結(jié)果如下:

?

?


Detected memory leaks!
Dumping objects ->
f:/test/memleakchecker/memleakchecker/memleakchecker.cpp(23) : {108} normal block at 0x0003A1A8, 10 bytes long.
?Data: CD CD CD CD CD CD CD CD CD CD
f:/test/memleakchecker/memleakchecker/memleakchecker.cpp(22) : {107} client block at 0x0003A160, subtype 0, 10 bytes long.
?Data: CD CD CD CD CD CD CD CD CD CD
f:/test/memleakchecker/memleakchecker/memleakchecker.cpp(21) : {106} client block at 0x0003A120, subtype 0, 1 bytes long.
?Data: 00
Object dump complete.


下面是一些注意事項(xiàng):
(1) #define _CRTDBG_MAP_ALLOC 的作用
如果不定義這個(gè)宏, C方式的malloc泄露不會(huì)被記錄下來。

?

(2)數(shù)字{108} {107}的作用
表示第幾次分配, 你可以通過_CrtSetBreakAlloc程序運(yùn)行到預(yù)定次數(shù)時(shí)暫停 ,比如


int _tmain(int argc, _TCHAR* argv[])
{
??? _CrtSetBreakAlloc(108);

?

??? char* p = new char();
??? char* pp = new char[10];
??? char* ppp = (char*)malloc(10);

??? _CrtDumpMemoryLeaks();

??? return 0;
}


(3)如果程序有多個(gè)出口或是有涉及到全局變量, 可以通過_CrtSetDbgFlag 設(shè)置標(biāo)志讓程序退出時(shí)自動(dòng)打印泄露 , 比如

?

?


int _tmain(int argc, _TCHAR* argv[])
{
??? _CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );

?

??? char* p = new char();
??? char* pp = new char[10];
??? char* ppp = (char*)malloc(10);

??? return 0;
}


(4)我們知道宏替代是最粗暴的方式, 所以盡量把下面new的替代宏放到每個(gè)Cpp里而不是放到一個(gè)通用的頭文件中, 實(shí)際上MFC也是這么做的

?

?


#ifdef _DEBUG
#define new DEBUG_CLIENTBLOCK
#endif


(5)上面的operator new只能照顧到最普通的new, 實(shí)際上operator new是有任意多種重載方式, 只需要確保第一個(gè)參數(shù)是表示大小。 比如下面的placement new就會(huì)編譯失敗, 因?yàn)楹晏娲蟾袷讲环弦罅耍?所以如果你的CPP用了非標(biāo)準(zhǔn)的new, 就不要加入new的檢測(cè)宏了。

?

?


#include

?

#ifdef _DEBUG
#define DEBUG_CLIENTBLOCK?? new( _CLIENT_BLOCK, __FILE__, __LINE__)
#else
#define DEBUG_CLIENTBLOCK
#endif
#define _CRTDBG_MAP_ALLOC
#include
#ifdef _DEBUG
#define new DEBUG_CLIENTBLOCK
#endif


int _tmain(int argc, _TCHAR* argv[])
{
??? _CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );

??? char* p = new char();
??? char* pp = new char[10];
??? char* ppp = (char*)malloc(10);

??? char d;
??? char* p1 = new(&d) char('a');

??? return 0;
}


(6)因?yàn)镾TL里map內(nèi)的tree用到了placement new,? 所以如果你這樣用會(huì)編譯失敗:

?

?


#ifdef _DEBUG
#define DEBUG_CLIENTBLOCK?? new( _CLIENT_BLOCK, __FILE__, __LINE__)
#else
#define DEBUG_CLIENTBLOCK
#endif
#define _CRTDBG_MAP_ALLOC
#include
#ifdef _DEBUG
#define new DEBUG_CLIENTBLOCK
#endif

?

#include


你應(yīng)該把 #include 放到 宏定義的前面。

?

(7) 如果你在宏 #define new DEBUG_CLIENTBLOCK 之后再聲明或定義 operator new函數(shù), 都會(huì)因?yàn)楹晏娲幾g失敗。
而STL的xdebug文件恰恰申明了operator new函數(shù), 所以請(qǐng)確保new的替代宏放在所有include頭文件的最后, 尤其要放在STL頭文件的后面。


//MyClass.cpp
#include "myclass.h"
#include
#include

?

#ifdef _DEBUG
#define new DEBUG_CLIENTBLOCK
#endif

MyClass::MyClass()
{
??? char* p = new char('a');
}


(8)如果你覺得上面的這種new替代宏分散在各個(gè)CPP里太麻煩, 想把所有的東西放到一個(gè)通用頭文件里,請(qǐng)參考下面定義的方式:

?

?


//MemLeakChecker.h
#include
#include
//other STL file

?

#ifdef _DEBUG
#define DEBUG_CLIENTBLOCK?? new( _CLIENT_BLOCK, __FILE__, __LINE__)
#else
#define DEBUG_CLIENTBLOCK
#endif
#define _CRTDBG_MAP_ALLOC
#include
#ifdef _DEBUG
#define new DEBUG_CLIENTBLOCK
#endif


(9)簡(jiǎn)單判斷某個(gè)獨(dú)立函數(shù)有沒有內(nèi)存泄露可以用下面的方法:

?

?


class DbgMemLeak
{
??? _CrtMemState m_checkpoint;

?

public:
??? explicit DbgMemLeak()
??? {??
??????? _CrtMemCheckpoint(&m_checkpoint);
??? };

??? ~DbgMemLeak()
??? {
??????? _CrtMemState checkpoint;
??????? _CrtMemCheckpoint(&checkpoint);
??????? _CrtMemState diff;
??????? _CrtMemDifference(&diff, &m_checkpoint, &checkpoint);
??????? _CrtMemDumpStatistics(&diff);
??????? _CrtMemDumpAllObjectsSince(&diff);
??? };
};


int _tmain(int argc, _TCHAR* argv[])
{
??? DbgMemLeak check;
??? {
??????? char* p = new char();
??????? char* pp = new char[10];
??????? char* ppp = (char*)malloc(10);
??? }

??? return 0;
}


(10) 其實(shí)知道了原理, 自己寫一套C++內(nèi)存泄露檢測(cè)也不難, 主要是重載operator new和operator delete, 可以把每次內(nèi)存分配情況都記錄在一個(gè)Map里, delete時(shí)刪除記錄, 最后程序退出時(shí)把map里沒有delete的打印出來。 當(dāng)然我們知道Crt在實(shí)現(xiàn)new時(shí)一般實(shí)際上調(diào)的是malloc, 而malloc可能又是調(diào)HeapAlloc,而HeapAlloc可能又是調(diào)用RtlAllocateHeap, 所以理論上我們可以在這些函數(shù)的任意一層攔截和記錄。但是如果你要實(shí)現(xiàn)自己的跨平臺(tái)內(nèi)存泄露檢測(cè),還是重載operator new吧,更多精彩內(nèi)容,盡在武林技術(shù)頻道。

發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 昆明市| 阿荣旗| 邹平县| 寿光市| 南京市| 富源县| 徐闻县| 凤城市| 灵宝市| 大竹县| 朔州市| 湘乡市| 象山县| 漯河市| 凌源市| 竹北市| 昭平县| 万年县| 洞头县| 山丹县| 榆中县| 兴山县| 米泉市| 临沭县| 延安市| 海安县| 保靖县| 涟源市| 冷水江市| 津市市| 巴东县| 大庆市| 湘潭县| 肥西县| 长白| 邳州市| 邳州市| 老河口市| 汕头市| 徐闻县| 微山县|