C ++ Memory Leak无法正常显示

时间:2013-01-28 05:22:47

标签: c++ memory-leaks memory-leak-detector

我正在使用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?

4 个答案:

答案 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()机制连接的函数释放它们。