【问题标题】:C++ Memory Leak not properly showingC++ 内存泄漏未正确显示
【发布时间】:2013-01-11 10:18:54
【问题描述】:

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

这会从类中删除新的字符以防止内存泄漏,还是我也应该在 charPointer 上调用 delete?

【问题讨论】:

  • 因为你删除的是things,而不是指针,所以当你删除它时,哪个指针指向某个东西并不重要。换句话说,通过anotherPointer删除与通过charPointer删除是一样的,你应该只做其中一个。
  • 好的。是整个问题都变了还是我变了?

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


【解决方案1】:

如果您想捕获(或有机会捕获)全局对象泄漏,请尝试在 main.js 的开头设置 CRT 调试标志 _CRTDBG_LEAK_CHECK_DF。该标志强制转储检测到的泄漏全局析构函数之后。

回答您的问题:

自从我的程序退出后(就在 _CrtDumpMemoryLeaks() 之后)并且还有一个新字符没有被删除,我不应该收到警告吗?

定义“警告”。对_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 分配的对象转储。

【讨论】:

    【解决方案2】:

    考虑一下。全局变量myClass 具有静态存储持续时间。当程序终止时,它将在main 的右大括号之后被销毁。 _CrtDumpMemoryLeaks() 不能肯定地检测到是泄漏,因为 MyClass 的析构函数还没有(正确地)被调用。

    【讨论】:

      【解决方案3】:

      自从我的程序退出后我不应该收到警告吗(就在_CrtDumpMemoryLeaks()之后)

      是的,你应该得到一个警告,但不是因为退出,...

      还有一个新的字符没有被删除?

      ...但是正因为如此,也就是因为还有一个动态分配的char数组没有被删除。

      如何检测这些内存泄漏?

      你确定你用 _DEBUG #defined 编译了程序吗?如果你这样做了,afaik 它应该被检测到。 (现在无法检查自己,并且已经很久没有使用它了,所以我不能保证这一点。)

      另外,使用上面相同的示例,如果我添加代码:

      char* anotherPointer = charPointer; //previously filled delete[] 另一个指针;`

      这会从类中删除新的字符以防止内存泄漏,还是我也应该在 charPointer 上调用 delete?

      这将删除动态分配的字符数组。在此charPointer 之后是一个悬空指针,它不能再被使用——既不能取消引用,也不能删除[]。 (同样适用于anotherPointer。)再次删除删除的数组,无论是通过相同的指针还是另一个变量都是不允许的,并导致Undefined Behavior

      【讨论】:

        【解决方案4】:

        您是否正在链接调试库?如果不是,您将不会收到有关未释放内存块的消息。提示:使用 /MDd 选项。

        请注意,与函数名称所暗示的相反,它所做的只是打印尚未释放的内存块列表。通过在 main() 的末尾调用它,您可以让它报告您明确分配但没有明确释放的块。因此,如果您动态分配了单例对象,它们将被报告为泄漏,而您可能会使用通过 _atexit() 机制连接的函数来合理地释放它们。

        【讨论】:

          猜你喜欢
          • 2011-10-10
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-06-20
          • 1970-01-01
          • 2019-07-17
          • 2016-01-27
          • 2010-11-11
          相关资源
          最近更新 更多