C++内存泄漏未正确显示

C++ Memory Leak not properly showing

本文关键字:显示 内存 泄漏 C++      更新时间:2023-10-16

我正在使用 _CrtDumpMemoryLeaks(); 从 stdlib.h 和 crtdbg.h 来检测内存泄漏,但我注意到我的代码中有一些奇怪的东西。

如果我这样做:

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?

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

要回答您的问题:

我不应该收到警告,因为我的程序退出了(紧跟在 _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.

请注意,第一个转储只记录内部分配,因为我使用了检查点,然后是转储自调用。第二个转储(在main()完成后调用)仍然记录它们,因为它们都非常出色。

在动态分配(授予来自全局内存空间中的对象,但与分配无关,它只是代码分配内存并将其返回给您)后,您是泄漏转储看起来不正确。您应该获得程序启动以来所有未完成 CRT 分配的对象转储以及任何_CrtDumpMemoryLeaks()调用。

想一想。全局变量myClass具有静态存储持续时间。当程序终止时,它将在main的闭合大括号后被销毁。 _CrtDumpMemoryLeaks () 无法肯定地检测到泄漏,因为尚未(正确)调用MyClass的析构函数。

自从我的程序退出以来,我不应该收到警告吗(右after_CrtDumpMemoryLeaks())

是的,您应该收到警告,但不是因为退出,...

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

。但正因为如此,即因为仍然有一个动态分配的 char 数组没有被删除。

如何检测这些内存泄漏?

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

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

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

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

这将删除动态分配的字符数组。在此charPointer之后是一个悬空指针,不得再使用它 - 既不能取消引用,也不能删除[]'d。 (这同样适用于anotherPointer。 不允许再次删除已删除的数组,无论是通过同一指针还是其他变量,这都会导致未定义的行为。

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

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