gpt4 book ai didi

c++ - 对 MFC 项目中的内存泄漏感到困惑,如果从未调用 _CrtDumpMemoryLeaks() 就会消失

转载 作者:搜寻专家 更新时间:2023-10-31 01:27:04 28 4
gpt4 key购买 nike

我有一个基于 MFC (C++) 对话框的项目,该项目是使用 Visual Studio 2017 编译的。我添加了以下代码以在构建它时跟踪可能的内存泄漏:

在初始化我的 CWinApp 派生类之前从 ProjectName.cpp 中获取。

#define _CRTDBG_MAP_ALLOC  
#include <stdlib.h>
#include <crtdbg.h>
#include <Wtsapi32.h>
#pragma comment(lib, "Wtsapi32.lib")


struct CatchMemLeaks{
CatchMemLeaks()
{
HANDLE ghDebugLogFile = ::CreateFile(L".\\dbg_output.txt",
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);

//Enable logging into that file
_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
_CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE | _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE));
_CrtSetReportFile(_CRT_WARN, ghDebugLogFile);
_CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE | _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE));
_CrtSetReportFile(_CRT_ERROR, ghDebugLogFile);
_CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE | _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE));
_CrtSetReportFile(_CRT_ASSERT, ghDebugLogFile);


//Try to break on the error reported
_CrtSetBreakAlloc(75);
}

~CatchMemLeaks()
{
if(_CrtDumpMemoryLeaks())
{
DWORD dwRespMsgBx;
::WTSSendMessage(NULL, ::WTSGetActiveConsoleSessionId(),
L"MemLeak", lstrlen(L"MemLeak") * sizeof(WCHAR),
L"MemLeak", lstrlen(L"MemLeak") * sizeof(WCHAR),
MB_OK | MB_ICONERROR | MB_SYSTEMMODAL,
0, &dwRespMsgBx, TRUE);
}
}
};

CatchMemLeaks cml;



//Then the usual MFC CWinApp-app derived class stuff:
// CProjectNameApp

BEGIN_MESSAGE_MAP(CProjectNameApp, CWinApp)
ON_COMMAND(ID_HELP, &CWinApp::OnHelp)
END_MESSAGE_MAP()


// CProjectNameApp construction

CProjectNameApp::CProjectNameApp()
{
// support Restart Manager
m_dwRestartManagerSupportFlags = AFX_RESTART_MANAGER_SUPPORT_RESTART;

// TODO: add construction code here,
// Place all significant initialization in InitInstance
}


// The one and only CProjectNameApp object

CProjectNameApp theApp;

//....

然后当项目运行然后退出时,我的 WTSSendMessage 被触发:

enter image description here

这给了我以下输出:

Detected memory leaks!
Dumping objects ->
{75} normal block at 0x0000029BA5EA75D0, 16 bytes long.
Data: < G > B0 86 D0 47 F7 7F 00 00 00 00 00 00 00 00 00 00
{74} normal block at 0x0000029BA5ECE930, 48 bytes long.
Data: <0 0 > 30 E9 EC A5 9B 02 00 00 30 E9 EC A5 9B 02 00 00
{73} normal block at 0x0000029BA5EA82F0, 16 bytes long.
Data: <p G > 70 86 D0 47 F7 7F 00 00 00 00 00 00 00 00 00 00
{72} normal block at 0x0000029BA5ECEA80, 48 bytes long.
Data: < > 80 EA EC A5 9B 02 00 00 80 EA EC A5 9B 02 00 00
{71} normal block at 0x0000029BA5EA8070, 16 bytes long.
Data: < G > 20 86 D0 47 F7 7F 00 00 00 00 00 00 00 00 00 00
{70} normal block at 0x0000029BA5E98BA0, 120 bytes long.
Data: < > A0 8B E9 A5 9B 02 00 00 A0 8B E9 A5 9B 02 00 00
Object dump complete.

但是在下一次调试运行中,当我添加上面代码中显示的 _CrtSetBreakAlloc(75); 行时,错误 75 上的断点永远不会触发,尽管输出仍然保持不变。

另一个有趣的发现是,如果我从 ~CatchMemLeaks 析构函数中删除 _CrtDumpMemoryLeaks() 函数,那些内存泄漏就会消失。

附言。我知道这对于这个特定项目来说是特殊的,因为如果我使用基于 MFC 对话框的现有应用程序尝试它,我不会得到相同的行为。

知道如何跟踪这些泄漏的来源吗?

最佳答案

天哪,我明白了。 (感谢评论中的 @RbMm!)要点是让这个泄漏检测代码在所有其他 CRT 和 MFC 构造函数和其他东西之前初始化(并在之后取消初始化)。诀窍是使用 #pragma init_seg(compiler) 指令。我最初的错误是在定义了 CWinApp 派生类的 .cpp 文件中使用它。这会在应用程序退出时导致崩溃,因为该 #pragma 指令适用于整个 .cpp 文件。

所以解决方案是为我的 CatchMemLeaks 类创建一个单独的 .h.cpp 文件并设置 #pragma 指令,如下所示:

CatchMemLeaks.h 文件:

#pragma once

//Only debugger builds
#ifdef _DEBUG

#define _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>

#include <Strsafe.h>
#include <Wtsapi32.h>
#pragma comment(lib, "Wtsapi32.lib")


struct CatchMemLeaks{
CatchMemLeaks(int nMemLeakCodeToCatch);
~CatchMemLeaks();
};

#endif

CatchMemLeaks.cpp文件:

#include "StdAfx.h"
#include "CatchMemLeaks.h"

//Only debugger builds
#ifdef _DEBUG

#pragma warning( push )
#pragma warning( disable : 4074)
#pragma init_seg(compiler) //Make this code execute before any other code in this project (including other static constructors).
//This will also make its destructors run last.
//WARNING: Because of this do not call any CRT functions from this .cpp file!
#pragma warning( pop )

CatchMemLeaks cml(0); //Set to (0) to monitor memory leaks, or to any other value to break on a specific leak number




CatchMemLeaks::CatchMemLeaks(int nMemLeakNumberToBreakOn)
{
HANDLE ghDebugLogFile = ::CreateFile(.\\dbg_output.txt,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);

//Enable logging into that file
_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
_CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE | _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE));
_CrtSetReportFile(_CRT_WARN, ghDebugLogFile);
_CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE | _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE));
_CrtSetReportFile(_CRT_ERROR, ghDebugLogFile);
_CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE | _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE));
_CrtSetReportFile(_CRT_ASSERT, ghDebugLogFile);

if(nMemLeakNumberToBreakOn)
{
_CrtSetBreakAlloc(nMemLeakNumberToBreakOn);
}
}

CatchMemLeaks::~CatchMemLeaks()
{
//Dump memory leaks, if any
if(_CrtDumpMemoryLeaks())
{
DWORD dwRespMsgBx;
::WTSSendMessage(NULL, ::WTSGetActiveConsoleSessionId(),
L"MemLeak", lstrlen(L"MemLeak") * sizeof(WCHAR),
L"MemLeak", lstrlen(L"MemLeak") * sizeof(WCHAR),
MB_OK | MB_ICONERROR | MB_SYSTEMMODAL,
0, &dwRespMsgBx, TRUE);
}
}

#endif

然后最后将其包含在 stdafx.h 文件中:

#include "CatchMemLeaks.h"  

关于c++ - 对 MFC 项目中的内存泄漏感到困惑,如果从未调用 _CrtDumpMemoryLeaks() 就会消失,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54105801/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com