必须调用_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF)并包含,且仅在_DEBUG下生效;{123}是分配序号而非源码行号,需配合_CrtSetBreakAlloc(123)定位。

Visual Studio 调试器中开启内存泄漏检测必须加 _CrtSetDbgFlag
默认情况下,VS 的 C 运行时(CRT)不会自动报告内存泄漏,哪怕你用了 new 没配 delete。关键动作是手动启用调试堆并设置报告级别——最常用的是在 main() 开头或 WinMain() 里调用:
_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
注意两点:
• 必须包含 头文件,且仅在 _DEBUG 宏定义下生效;
• _CRTDBG_LEAK_CHECK_DF 表示程序退出时自动检查泄漏,不是实时监控;
• 如果只设了 _CRTDBG_ALLOC_MEM_DF 而没加泄漏检查标志,运行结束时不会输出任何泄漏信息。
泄漏报告里的 {123} 行号不是源码行号,而是分配序号
VS 输出的泄漏信息形如:
Detecting memory leaks...
Detected memory leaks!
Dumping objects ->
{18} normal block at 0x00B9A568, 4 bytes long.
Data: < > CD CD CD CD
这个
{18} 是 CRT 内部按分配顺序给的编号,不是你代码第 18 行。要定位源头,得配合 _CrtSetBreakAlloc(18) 在第 18 次分配时中断:_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
_CrtSetBreakAlloc(18); // 加在 main 开头,运行后会在该次 new/malloc 处中断
常见误区:
• 直接看泄漏报告里“file:line”字段——它只对用 _malloc_dbg 或重载了带文件/行号参数的 operator new 才有效;
• 忘记在 Debug 模式下编译:Release 模式下 _Crt*() 函数全为空操作;
• 在 DLL 中初始化时调用太早(比如 DLL_PROCESS_ATTACH 里),此时 CRT 堆可能还没准备好。
立即学习“C++免费学习笔记(深入)”;
C++ 类中重载 operator new 才能获得精准文件名和行号
标准 new 不传位置信息,所以 CRT 默认无法记录调用点。想让泄漏报告直接显示 myfile.cpp(42),需全局或按类重载带调试参数的版本:
#ifdef _DEBUG
void* operator new(size_t size, const char* file, int line) {
return _malloc_dbg(size, _NORMAL_BLOCK, file, line);
}
#define new new(__FILE__, __LINE__)
#endif
实际使用时要注意:
• 宏定义 #define new 必须放在所有头文件之后、你的源文件代码之前(常放在 stdafx.h 尾或单独的 debug_new.h 中);
• 第三方库如果也重载了 operator new,可能冲突,此时建议只在自己的模块中局部启用;
• std::vector、std::string 等 STL 容器内部分配通常不走你的重载(除非自定义 allocator),它们的泄漏仍显示为 {N} 序号。
VS 的「诊断工具」窗口只能看到堆大小趋势,不能定位具体泄漏点
按 Ctrl+Alt+F2 打开诊断工具后,内存使用曲线和快照对比对性能分析有用,但快照里列出的对象类型(如 “std::string”、“char[]”)不带分配栈,也无法关联到源码行。它和 CRT 泄漏检测是两套机制:
• CRT 报告依赖调试堆标记,输出文本到输出窗口;
• 诊断工具基于 ETW 事件采集,更轻量但信息粒度粗;
• 若项目启用了 /MT(静态链接 CRT),而诊断工具期望动态 CRT,则可能完全不显示托管/本地内存混合视图。
真正能定位到哪一行 new 没配 delete 的,还是靠 _CrtSetBreakAlloc 配合断点,或者用第三方工具如 Visual Leak Detector(VLD),它会自动 hook 所有分配路径并打印完整调用栈。








