我正在使用stdlib.h和crtdbg.h中的 _CrtDumpMemoryLeaks(); 来检测内存泄漏,但我发现代码中有些奇怪。
如果我这样做:
int _tmain(int argc, _TCHAR* argv[])
{
MyClass* myClass = new MyClass();
_CrtDumpMemoryLeaks(); //I get a memory leak warning
}
但是,如果我这样做:
class MyClass
{
public:
char* NewChar();
};
char* MyClass::NewChar()
{
char* test = new char[100];
return test;
}
MyClass myClass; //Globally declared
int _tmain(int argc, _TCHAR* argv[])
{
char* charPointer = myClass.NewChar();
_CrtDumpMemoryLeaks(); //No warnings
}
自我的程序退出后(在 _CrtDumpMemoryLeaks()之后),我不应该收到警告吗?还有一个新的字符未被删除?
如何检测这些内存泄漏?
另外,使用上面的相同示例,如果我添加代码:
char* anotherPointer = charPointer; //previously filled
delete[] anotherPointer;
这会从类中删除新的char以防止内存泄漏,还是应该在 charPointer 上调用delete?
答案 0 :(得分:2)
如果你想抓住(或者有很好的捕获)全局对象泄漏,请尝试在main的开头设置CRT调试标志 _CRTDBG_LEAK_CHECK_DF 。该标志强制在全局析构函数之后转储检测到的泄漏。
回答你的问题:
自我的程序退出后(在_CrtDumpMemoryLeaks()之后)我是否应该收到警告并且还有一个未删除的新char?
定义“警告”。对_CrtDumpMemoryLeaks()
的调用应该转储当时未完成的任何内容。除非经过配置,否则您之后退出的程序将不会执行另一次转储。
如何检测这些内存泄漏?
如果您正在使用调试CRT并正确配置_Crt
配置,那么它们应该被正确检测到,默认情况下它主要是 。
以下代码设置_Crt
转储系统,以便在最终退出之前(在main()
完成并且销毁全局静态之后)按需转储所有对象。
class MyLeak
{
public:
MyLeak() { new unsigned char[1024]; }
char * NewChar() { return new char[1024]; }
};
MyLeak myLeak;
int main(int argc, char *argv[])
{
int tmpFlag = _CrtSetDbgFlag( _CRTDBG_REPORT_FLAG );
tmpFlag |= _CRTDBG_LEAK_CHECK_DF;
_CrtSetDbgFlag(tmpFlag);
_CrtMemState ms = {0};
_CrtMemCheckpoint(&ms);
char *ptr = myLeak.NewChar();
_CrtMemDumpAllObjectsSince(&ms);
OutputDebugString("Exiting main()\n");
return EXIT_SUCCESS;
}
调试输出日志
Dumping objects ->
{69} normal block at 0x000000000048B800, 1024 bytes long.
Data: < > CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD
Object dump complete.
Exiting main()
Detected memory leaks!
Dumping objects ->
{69} normal block at 0x000000000048B800, 1024 bytes long.
Data: < > CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD
{68} normal block at 0x000000000048B390, 1024 bytes long.
Data: < > CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD
Object dump complete.
请注意,第一个转储仅记录内部分配,因为我使用了检查点,然后是dump-since调用。第二个转储(在main()
完成后调用)仍然记录它们,因为它们都是未完成的。
你的动态分配后你是泄漏转储(授权是来自全局内存空间中的一个对象,但这与分配无关,它只是代码分配内存并将其返回给你)看起来不正确。自程序启动以来,您应该使用任何_CrtDumpMemoryLeaks()
调用获取所有未完成CRT分配的对象转储。
答案 1 :(得分:0)
想一想。全局变量myClass
具有静态存储持续时间。当程序终止时,它将在main
的右括号后被销毁。由于_CrtDumpMemoryLeaks
的析构函数尚未(正确地)被调用,MyClass
()无法肯定地检测到泄漏。
答案 2 :(得分:0)
我的程序退出后不应该收到警告(紧跟在_CrtDumpMemoryLeaks()之后)
是的,你应该收到警告,但不是因为退出,...
并且还有一个未被删除的新char?
...但正因为如此,即因为仍然有动态分配的 char数组未被删除。
如何检测这些内存泄漏?
您确定使用_DEBUG #defined编译了程序吗?如果你这样做了,应该检测到它。 (现在无法检查自己,并且多年没有使用过这个,所以我无法保证这一点。)
另外,使用上面的相同示例,如果我添加代码:
char* anotherPointer = charPointer; //previously filled
delete [] anotherPointer;`这会从类中删除新的char以防止内存泄漏,还是应该在charPointer上调用delete?
这将删除动态分配的字符数组。在此charPointer
之后是悬空指针,不能再使用它 - 既不会解除引用也不会删除[]'d。 (同样适用于anotherPointer
。)不允许再次删除已删除的数组,无论是通过相同的指针还是其他变量,都会导致Undefined Behavior。
答案 3 :(得分:0)
您是否与调试库链接?如果不是,您将无法获得有关未释放的内存块的消息。提示:使用/ MDd选项。
请注意,与函数名称所暗示的相反,它所做的只是打印一个尚未释放的内存块列表。通过在main()的末尾调用它,您可以报告您明确分配的块,但没有明确释放。因此,如果你有动态分配的单例对象,它们将被报告为泄漏,而你可能完全可以使用通过_atexit()机制连接的函数释放它们。