启用内存泄漏检测

检测内存泄漏是 C/c + + 调试器和 C 运行时库 (CRT) 的主要工具调试堆函数。

若要启用调试堆的所有函数,在 c + + 程序中,按以下顺序包含以下语句:

C++复制
#define _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>

#define 语句将 CRT 堆函数的基础版本映射到对应的调试版本。 如果您忽略#define语句,为内存泄漏转储不够详尽

包括crtdbg.h映射mallocfree到其调试版本中,函数_malloc_dbg_free_dbg,它们将跟踪内存分配和解除分配。 此映射只在包含 _DEBUG的调试版本中发生。 发布版本使用普通的 malloc 和 free 函数。

通过使用上面的语句启用调试堆函数后,将调用_CrtDumpMemoryLeaks之前应用程序退出时显示的内存泄漏报告的应用程序退出点。

C++复制
_CrtDumpMemoryLeaks();

如果您的应用程序有多个退出,无需手动设置_CrtDumpMemoryLeaks在每个退出点。 若要使自动调用_CrtDumpMemoryLeaks在每个退出点,将调用_CrtSetDbgFlag使用如下所示的位域对应用程序的开头:

C++复制
_CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );

默认情况下, _CrtDumpMemoryLeaks 将内存泄漏报告输出到 “输出”窗口的 “调试”窗格中。 如果使用库,该库可能会将输出重置到另一位置。

可以使用_CrtSetReportMode该报告重定向到其他位置,或返回到输出窗口如下所示:

C++复制
_CrtSetReportMode( _CRT_ERROR, _CRTDBG_MODE_DEBUG );

解释内存泄漏报告

如果应用没有定义_CRTDBG_MAP_ALLOC, _CrtDumpMemoryLeaks显示如下所示的内存泄漏报告:

cmd复制
Detected memory leaks!
Dumping objects ->
{18} normal block at 0x00780E80, 64 bytes long.
Data: < > CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD
Object dump complete.

如果您的应用程序定义_CRTDBG_MAP_ALLOC,内存泄漏报告如下所示:

cmd复制
Detected memory leaks!
Dumping objects ->
c:\users\username\documents\projects\leaktest\leaktest.cpp(20) : {18}
normal block at 0x00780E80, 64 bytes long.
Data: < > CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD
Object dump complete.

第二个报表显示首次分配泄漏的内存的文件名和行号。

该值指示是否定义_CRTDBG_MAP_ALLOC,内存泄漏报告将显示:

  • 内存分配编号,即18在示例
  • 块类型,normal在示例中。
  • 十六进制内存位置0x00780E80在示例中。
  • 块的大小64 bytes在示例中。
  • 块中前 16 个字节的数据(十六进制形式)。

内存块类型正常客户端,或CRT。 “普通块”是由程序分配的普通内存。 “客户端块”是由 MFC 程序用于需要析构函数的对象的特殊类型内存块。 MFC new 运算符根据正在创建的对象的需要创建普通块或客户端块。

“CRT 块”是由 CRT 库为自己使用而分配的内存块。 CRT 库处理这些块,解除分配,因此 CRT 块不会显示在内存泄漏报告中,除非使用 CRT 库的严重问题。

内存泄漏报告中绝对不会出现另外两个内存块类型。 一个释放的块是已释放,以便根据定义不会泄漏的内存。 忽略块是已显式标记要从内存泄漏报告中排除。

以前的技术确定内存泄漏的内存分配使用标准 CRTmalloc函数。 如果您的程序分配内存使用 c + +new运算符,但是,你可能只能看到文件名和行号位置operator new调用_malloc_dbg内存泄漏报告中。 若要创建更有用的内存泄漏报告,可以编写如下所示来报告进行分配的行的宏:

C++复制
#ifdef _DEBUG
#define DBG_NEW new ( _NORMAL_BLOCK , __FILE__ , __LINE__ )
// Replace _NORMAL_BLOCK with _CLIENT_BLOCK if you want the
// allocations to be of _CLIENT_BLOCK type
#else
#define DBG_NEW new
#endif

现在可以替换new运算符使用DBG_NEW在代码中的宏。 在调试版本中,DBG_NEW使用的全局重载operator new采用附加参数的块类型、 文件和行号。 重载new调用_malloc_dbg记录的额外信息。 内存泄漏报告显示文件名和行号泄漏的对象的分配位置。 发行版本仍然使用默认值new。 下面是技术的示例:

C++复制
// debug_new.cpp
// compile by using: cl /EHsc /W4 /D_DEBUG /MDd debug_new.cpp
#define _CRTDBG_MAP_ALLOC
#include <cstdlib>
#include <crtdbg.h> #ifdef _DEBUG
#define DBG_NEW new ( _NORMAL_BLOCK , __FILE__ , __LINE__ )
// Replace _NORMAL_BLOCK with _CLIENT_BLOCK if you want the
// allocations to be of _CLIENT_BLOCK type
#else
#define DBG_NEW new
#endif struct Pod {
int x;
}; void main() {
Pod* pPod = DBG_NEW Pod;
pPod = DBG_NEW Pod; // Oops, leaked the original pPod!
delete pPod; _CrtDumpMemoryLeaks();
}

在 Visual Studio 中运行此代码时调试器中调用_CrtDumpMemoryLeaks生成中的报表输出看起来类似于的窗口:

Output复制
Detected memory leaks!
Dumping objects ->
c:\users\username\documents\projects\debug_new\debug_new.cpp(20) : {75}
normal block at 0x0098B8C8, 4 bytes long.
Data: < > CD CD CD CD
Object dump complete.

此输出的第 20 行已泄漏的分配的报告debug_new.cpp

Note

我们不建议创建一个名为的预处理器宏new,或任何其他语言关键字。

内存分配编号上设置断点

如果分配了泄漏内存块,内存分配编号会通知你。 块内存分配编号为 18,例如,是内存的应用程序运行期间分配的第 18 块。 CRT 报告包含运行期间,其中包括 CRT 库和 MFC 等其他库由分配所有内存块分配情况。 因此,内存分配块编号 18 可能不是分配你的代码的第 18 内存块。

可以使用分配编号在内存分配位置设置断点。

若要设置使用监视窗口的内存分配断点:

  1. 您的应用程序的起点附近设置断点并开始调试。

  2. 当应用程序会在断点处暂停时,打开Watch通过选择窗口调试 > Windows > 监视 1(或观看 2,观看 3,或观看 4)。

  3. 在中Watch窗口中,键入_crtBreakAlloc中名称列。

    如果您使用的多线程的 DLL 版本的 CRT 库 (/MD 选项),添加上下文运算符: {,,ucrtbased.dll}_crtBreakAlloc

  4. 按 Enter。

    调试器将计算调用,并将结果放入 “值”列。 此值将为为-1如果你尚未在内存分配上设置任何断点。

  5. 在中值列中,值替换为要调试程序执行中断的内存分配的分配编号。

内存分配编号上设置断点后,继续调试。 请确保在相同条件下运行,因此不会更改的内存分配编号。 当应用程序在指定的内存分配处中断时,使用调用堆栈窗口和其他调试器窗口来确定分配内存时的情况。 然后,可以继续执行程序以观察对象会发生什么情况,并确定为什么它不正确释放。

在对象上设置数据断点可能也有帮助。 有关详细信息,请参阅使用断点

你也可以在代码中设置内存分配断点。 您可以设置:

C++复制
_crtBreakAlloc = 18;

或:

C++复制
_CrtSetBreakAlloc(18);

比较内存状态

定位内存泄漏的另一种技术涉及在关键点对应用程序的内存状态拍快照。 若要在应用程序中给定点处的内存状态的快照,创建_CrtMemState结构并将其传递给_CrtMemCheckpoint函数。

C++复制
_CrtMemState s1;
_CrtMemCheckpoint( &s1 );

_CrtMemCheckpoint函数填充在该结构的当前内存状态的快照。

若要输出的内容_CrtMemState结构,请将传递到结构_ CrtMemDumpStatistics函数:

C++复制
_CrtMemDumpStatistics( &s1 );

_ CrtMemDumpStatistics 输出内存状态转储,如下所示:

cmd复制
0 bytes in 0 Free Blocks.
0 bytes in 0 Normal Blocks.
3071 bytes in 16 CRT Blocks.
0 bytes in 0 Ignore Blocks.
0 bytes in 0 Client Blocks.
Largest number used: 3071 bytes.
Total allocations: 3764 bytes.

若要确定在某个代码部分中是否发生了内存泄漏,可以对这部分之前和之后的内存状态拍快照,然后使用 _ CrtMemDifference 比较两个状态:

C++复制
_CrtMemCheckpoint( &s1 );
// memory allocations take place here
_CrtMemCheckpoint( &s2 ); if ( _CrtMemDifference( &s3, &s1, &s2) )
_CrtMemDumpStatistics( &s3 );

_CrtMemDifference 比较内存状态s1s2,并返回结果中的 (s3),它是之间的差异s1s2

查找内存泄漏的一项技术开始上来_CrtMemCheckpoint的开头和结尾的您的应用程序,然后使用在调用_CrtMemDifference可以比较的结果。 如果_CrtMemDifference显示了内存泄漏,可以添加更多_CrtMemCheckpoint调用来划分程序使用二进制搜索,直到你已隔离找到泄漏源。

误报

_CrtDumpMemoryLeaks 如果库将内部分配标记为普通块而不是 CRT 块或客户端块可能给出错误地指示内存泄漏。 在这种情况下, _CrtDumpMemoryLeaks 无法区分用户分配和内部库分配。 如果在 _CrtDumpMemoryLeaks调用点之后运行库分配的全局析构函数,则每个内部库分配都会报告为内存泄漏。 版本早于可能会导致 Visual Studio.NET 的标准模板库_CrtDumpMemoryLeaks以报告此类的假正值。

请参阅

CRT 调试堆详细信息 
调试器安全 
调试本机代码

//======================================================================================================

引用页面地址及其他

https://docs.microsoft.com/zh-cn/visualstudio/debugger/finding-memory-leaks-using-the-crt-library?view=vs-2017

https://blogs.msdn.microsoft.com/vcblog/2015/10/21/memory-profiling-in-visual-c-2015/

https://blog.csdn.net/catshitone/article/details/79002823

Vc 检测内存泄漏的更多相关文章

  1. VC检测内存泄漏(Detected memory leaks!)

    Detected memory leaks!Dumping objects ->{98500} normal block at 0x05785AD0, 152 bytes long.Data: ...

  2. VC使用CRT调试功能来检测内存泄漏

    信息来源:csdn     C/C++ 编程语言的最强大功能之一便是其动态分配和释放内存,但是中国有句古话:“最大的长处也可能成为最大的弱点”,那么 C/C++ 应用程序正好印证了这句话.在 C/C+ ...

  3. 如何在linux下检测内存泄漏

    之前的文章应用 Valgrind 发现 Linux 程序的内存问题中介绍了利用Linux系统工具valgrind检测内存泄露的简单用法,本文实现了一个检测内存泄露的工具,包括了原理说明以及实现细节. ...

  4. 如何在linux下检测内存泄漏(转)

    本文转自:http://www.ibm.com/developerworks/cn/linux/l-mleak/ 本文针对 linux 下的 C++ 程序的内存泄漏的检测方法及其实现进行探讨.其中包括 ...

  5. Android性能优化之利用LeakCanary检测内存泄漏及解决办法

    前言: 最近公司C轮融资成功了,移动团队准备扩大一下,需要招聘Android开发工程师,陆陆续续面试了几位Android应聘者,面试过程中聊到性能优化中如何避免内存泄漏问题时,很少有人全面的回答上来. ...

  6. 使用Visual Leak Detector检测内存泄漏[转]

      1.初识Visual Leak Detector 灵活自由是C/C++语言的一大特色,而这也为C/C++程序员出了一个难题.当程序越来越复杂时,内存的管理也会变得越加复杂,稍有不慎就会出现内存问题 ...

  7. monkey检测内存泄漏

    monkey中检查内存泄漏,实际上是对一个操作多次操作后看内存情况,内存泄漏具体的原理可百度,现在我们梳理检测内存泄漏的方法: 测试前你需要安装: 1.MAT分析工具 2.使用工具事实监控内存指标,现 ...

  8. Qt creator 搭配 valgrind 检测内存泄漏

    继上次重载operator new检测内存泄漏失败之后,妥协了.决定不管是否是准确指明哪一行代码出现内存泄漏,只要告诉我是否有泄漏就行了,这样就没有new替换的问题.在开发中,总是一个个小功能的开发. ...

  9. 重载new和delete来检测内存泄漏

    重载new和delete来检测内存泄漏 1. 简述 内存泄漏属于资源泄漏的一种,百度百科将内存泄漏分为四种:常发性内存泄漏.偶发性内存泄漏.一次性内存泄漏和隐式内存泄漏.    常发性指:内存泄漏的代 ...

随机推荐

  1. oData 排序字段生成

    跟踪SQL 发现生成的SQL中所有的字段都进行了排序,查看OData原代码,发现如果实体有Key,就按照Key asc 加上指定字段进行排序 属性 EnsureStableOrdering可以控制是否 ...

  2. Linux服务器调教日常

    本文为Linux服务器调教日常,不保证正确. 1. sshd配置: https://www.cnblogs.com/byeyear/p/9289063.html 2. 禁止普通用户su 1. 编辑/e ...

  3. 涂抹mysql笔记-搭建mysql高可用体系

    mysql的高可用体系<>追求更高稳定性的服务体系 可扩展性:横向扩展(增加节点).纵向扩展(增加节点的硬件配置) 高可用性<>Slave+LVS+Keepalived实现高可 ...

  4. 如何使用jQuery从字符串中删除最后一个字符

    如何使用jQuery从字符串中删除最后一个字符 1.string.slice(0,-1) 2.str.substring(0,str.length-1)

  5. 关于element-ui日期选择器disabledDate使用心得

    实现目的: 使用type="data"类型实现具备开始日期与结束日期组件(ps:element有自带的type="daterange"类型的组件可以实现此功能) ...

  6. python解决SyntaxError: Non-ASCII character '\xe6'

    出现情况,输入如下一个函数demo: run,报错: SyntaxError: Non-ASCII character '\xe6' in file /Users/XX/PycharmProjects ...

  7. 手把手教你如何用 OpenCV + Python 实现人脸识别

    下午的时候,配好了OpenCV的Python环境,OpenCV的Python环境搭建.于是迫不及待的想体验一下opencv的人脸识别,如下文. 必备知识 Haar-like 通俗的来讲,就是作为人脸特 ...

  8. jdk 8 日期处理。

    ZoneId id = ZoneId.systemDefault(); LocalDateTime dateTime = LocalDateTime.now(id); System.out.print ...

  9. kubernets网络模式

    参考:https://www.kubernetes.org.cn/2059.html

  10. 批量移动AD用户到指定OU

    原文链接:http://blog.51cto.com/shubao/1346469 作为域管理员,在日常工作中使用ADUC(AD用户和计算机)工具在图形界面中进行账号管理操作可谓是家常便饭了.然而一个 ...