crt调试堆默认仅捕获malloc等c风格内存泄漏,不检测new/delete泄漏;要使其生效,必须在debug配置下于main开头调用_crtsetdbgflag(_crtdbg_alloc_mem_df | _crtdbg_leak_check_df),且程序需正常退出。

CRT调试堆能抓到malloc泄漏,但对new/delete默认静默——不重载operator new就等于没开全功能。
为什么_CrtDumpMemoryLeaks什么都没输出
常见原因不是代码没写,而是三个条件缺一不可:
- 项目必须是Debug配置,且链接器启用了
/DEBUG,C/C++选项中调试信息格式设为/Zi -
_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF)必须在main()最开头调用,不能被if包裹,也不能晚于任何malloc调用 - 程序得**正常退出**:如果中途
exit()、abort()、未捕获异常或调试时手动终止,泄漏报告就被跳过了
怎么让new/delete也进CRT报告
默认情况下,new走的是系统堆或标准operator new,完全绕过CRT调试堆。要让它也被追踪,必须手动重载:
- 在所有用到
new的.cpp文件都包含的头里(比如stdafx.h或common.h),加以下定义(仅_DEBUG下生效):
#ifdef _DEBUG
#define _CRTDBG_MAP_ALLOC
#include <crtdbg.h>
void* operator new(size_t size) {
return _malloc_dbg(size, _NORMAL_BLOCK, __FILE__, __LINE__);
}
void operator delete(void* ptr) noexcept {
_free_dbg(ptr, _NORMAL_BLOCK);
}
#endif</crtdbg.h>
注意:__FILE__和__LINE__才能让泄漏报告带出源码位置;如果漏掉noexcept,某些编译器会报错或链接失败。
泄漏报告里{123}是什么,怎么用
这个数字是分配序号,不是内存地址,也不是随机值——它是CRT内部按分配顺序给的唯一ID。它的实际用途很直接:
- 在泄漏报告里看到
{123},就在main()开头加一句_CrtSetBreakAlloc(123); - 下次调试运行,程序会在第123次
malloc或重载后的new处自动中断,停在分配那一行 - 如果泄漏发生在多线程环境,这个序号仍有效,但需确保
_CrtSetBreakAlloc在目标线程执行前已设置(通常放main最前最稳)
Qt项目里容易漏掉的QObject泄漏
即使CRT报告“无泄漏”,Qt对象也可能堆积——因为QObject析构不触发CRT堆释放,它靠父子树自动清理。典型表现是程序退出后QObject::findChildren<qobject>()</qobject>返回非空列表:
- 在
app.exec()之后、return之前插入检查代码:
QObjectList objects = QObject::findChildren<qobject>(); qDebug() <p>输出大于0,说明有<code>QObject</code>没设父对象也没调<code>deleteLater()</code>。尤其注意<code>QThread</code>、<code>QTimer</code>、自定义<code>QObject</code>子类这些常被手动<code>new</code>却忘记挂靠的对象。</p></qobject>
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











