用V C++检测和隔离内存泄漏
设置内存泄漏检测
检测内存泄漏的基本工具是调试器和CRT调试堆函数。为了使用调试堆函数,在你的程序中你必须含有下面的说明:
#define _CRTDBG_MAP_ALLOC#include <stdlib.h>#include <crtdbg.h>
#include说明必须按顺序说明。如果改变了顺序,所用的函数可能不能正常工作。包含crtdbg.h的_malloc_dbg和 _free_dbg将 malloc和free函数映射到测试版中,它可以跟踪内存的分配和释放。这种映射仅仅在一个测试体系中发生(也就是说,仅仅当_DEBUG被定义的时候)。释放的体系使用通常的malloc和 free功能。
#define说明映射CRT堆函数的低级版本到相应的测试版本。这个说明是不需要的,但是没有它,内存泄漏处含有的只是没有多大用处的信息。
一旦你已经增加了刚才的说明,你能够通过在你的程序中包含下面的说明来释放内存信息:
_CrtDumpMemoryLeaks();
当调试情况下运行程序时,在输出窗口的Debug 标签处_CrtDumpMemoryLeaks表现出内存泄漏的信息。内存泄漏信息类似下面这样:
Detected memory leaks!
Dumping objects ->
C:/PROGRAM FILES/VISUAL STUDIO/MyProjects/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.
如果你没有用#define _CRTDBG_MAP_ALLOC说明,内存漏洞堆存处类似下面这样:
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被定义时,_CrtDumpMemoryLeaks给了你更多的有用信息。如果_CRTDBG_MAP_ALLOC没有被定义,那么将向你如下显示:
内存分配数值(花括号内)
模块的类型(normal、client或者CRT)
以十六进制格式定位的内存
以字节计模块的大小
第一个十六字节的内容(也可以用十六进制)
当定义了_CRTDBG_MAP_ALLOC的时候,显示的内容也向你展现了出现泄漏内存所分配地方的文件。在文件名之后括号内的数字(20,以此为例)是文件内的行数值。如果你双击包含行数值和文件名的输出行,
C:/PROGRAM FILES/VISUAL STUDIO/MyProjects/leaktest/leaktest.cpp(20) : {18} normal block at
0x00780E80, 64 bytes long.
指针将会跳到源文件中内存被分配地方的行(在上面的情况下,leaktest.cpp的行号为20)。选择输出行并按F4将有同样的效果。
使用_CrtSetDbgFlag
如果你的程序总是在同一各地方存在,那么调用_CrtDumpMemoryLeaks时非常容易的。但是,如果你的程序需要在多个位置退出该怎么办?在每一个可能的出口处如果不调用_CrtDumpMemoryLeaks,你可在你的程序开始处包含下面的调用:
_CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
当程序退出时,这个说明自动地调用_CrtDumpMemoryLeaks。你必须设置两个位域,_CRTDBG_ALLOC_MEM_DF和 _CRTDBG_LEAK_CHECK_DF。
翻译内存模块的类型
内存泄漏信息鉴别泄漏内存的每一个模块作为一个普通的模块、一个客户模块或者一个CRT模块。实际上,普通的模块和客户模块是你可能留心的唯一类型。
一个普通模块(normal block)是由你的程序分配的普通内存。
一个客户模块(client block)是一种特殊的内存模块,它由于需要一个析构函数的对象而被Microsoft Foundation Classes (MFC)所使用。MFC new操作子建立一个普通模块或者一个客户模块,来适合被创建的模块。
一个CTR模块是由CRT库提供自己使用而分配的内存模块。CRT库对这些模块来管理自己的去分配,因此你不可能在内存泄漏报告中注意到这些,除非有些地方有严重的错误(例如,CRT库崩溃)。
在内存泄漏信息中有两种你从来没有见过的模块类型:
空闲模块(free block)是一种被释放的内存模块
Ignore block是你已经特殊标记过以至于在内存泄漏报告中不会出现的模块。
设置CRT报告样式
像以前的一样,按默认方式,_CrtDumpMemoryLeaks倾卸内存泄漏信息到输出窗口的Debug窗格。你可以运用_CrtSetReportMode重新设置它到堆存处,到另一个位置。如果你使用一个库,它可能重新设置输出到另一个位置。在这种情况下,你能够利用下面的说明来设置输出位置回到输出窗口:
_CrtSetReportMode( _CRT_ERROR, _CRTDBG_MODE_DEBUG );
关于使用_CrtSetReportMode去发送输出信息到另一个位置,要看Visual C++文件的_CrtSetReportMode节。
在内存分配数目处设置一个断点
在内存泄漏报告中的文件名和行号可告诉你泄漏的内存在那里被分配,但是了解内存在那里分配对于鉴定问题不总是充分的。在一个程序运行过程中,经常是一个分配将会被调用很多次,但是它可能在某次调用中泄漏内存。为了确定问题,你必须不但知道泄漏的内存在那里分配,还要知道泄漏发生的条件。对你来说,使它成为可能的那条信息是内存分配号。当那些被显示的时候,文件名和行号之后,这是在curly brace中出现的数值。例如,在下面的输出中,"18"是内存分配号。它的意思是泄漏的内存是你程序中内存分配的第十八个模块。
Detected memory leaks!
Dumping objects ->
C:/PROGRAM FILES/VISUAL STUDIO/MyProjects/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.
CRT库计算在程序运行期间分配的所用内存模块,包括CRT自己分配的内存或者诸如MFC的其它模块。因此带有分配号n的一个对象是在你的程序中分配的第n个对象,但不可能是由代码分配的第n个对象。(在大部分情况下,它是不会的。)
你可以利用分配号在内存分配的地方设置一个断点。为了做这些,你可以距离你的程序开始很近处,设置一个位置断点。当你的程序在那一点暂停时,你能够从QuickWatch对话框或者Watch窗口设置这样一个位置断点。例如,在Watch窗口中,在Name栏键入下面的表达式:
_crtBreakAlloc
如果你正在用CRT库的多线程的dynamic-link library (DLL)版本,你必须含有上下文操作符,像这里说明的:
{,,msvcrtd.dll}_crtBreakAlloc
现在,按RETURN。调试器评估调用并且把结果放置在Value栏。如果你在内存分配过程中还没有设置任何断点,那么这个值是-1。使用你想中断处内存分配的分配数值来代替Value表中的值--例如,18 去中断早期在输出过程中展现的分配。
当你在你感兴趣的内存分配处设置断点之后,你能够继续调试。在与从前相同的条件下,运行程序时一定要小心,因而分配的顺序不会改变。当你的程序在一个特殊的内存分配点中断的时候,你能够查看Call Stack窗口和其他的测试信息来确定在此条件下内存的分配。如果需要的话,你可以继续从那一点执行程序,以至于了解对象到底发生了什么事,同时还可能确定为了没有正确地被去分配。(对对象设置一个数据断点是很有帮助的。)
虽然在调试器中设置内存分配断点通常更加容易,但是如果你喜欢的话,你可以在你的代码中设置它们。为了在你的代码中设置一个内存分配断点,可以增加这样一行(对于第十八个内存分配):
_crtBreakAlloc = 18;
最为一个选择,你可以使用有相同效果的_CrtSetBreakAlloc函数。
_CrtSetBreakAlloc(18);
比较内存状态
定位内存泄漏的另一个方法就是在关键点对应用程序的内存状态做快照。CRT库提供了一个结构类型,_CrtMemState。你可以使用它来存储内存状态的一个快照。
_CrtMemState s1, s2, s3;
为了在特定点对内存状态进行快照,可以传递一个_CrtMemState结构到he _CrtMemCheckpoint函数。此函数用当时内存状态的一个快照来填充此结构:
_CrtMemCheckpoint( &s1 );
你可以通过传递此结构到_CrtMemDumpStatistics函数来倾卸_CrtMemState结构的任意点的内容:
_CrtMemDumpStatistics( &s3 );( &s1 );
此函数打印出类似于下面这样的一堆内存分配信息:
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比较两种状态:
_CrtMemCheckpoint( &s1 );
// memory allocations take place here
_CrtMemCheckpoint( &s2 );
if ( _CrtMemDifference( &s3, &s1, &s2) )
_CrtMemDumpStatistics( &s3 );
像名字暗示的一样,_CrtMemDifference比较两个内存状态(最先的两个参数)并且产生一个不同于这两个状态的结果(第三个参数)。在你的程序开始和结尾处的_CrtMemCheckpoint调用和使有_CrtMemDifference来比较结果为检测内存泄漏提供了另一种方法。如果一个泄漏被检测到,那么可以使用_CrtMemCheckpoint调用来分割你的程序并且使用二元binary search technique来定位泄漏。
用V C++检测和隔离内存泄漏相关推荐
- 如何检测和处理内存泄漏
四. 如何检测和处理内存泄漏 如何查找引起内存泄漏的原因一般有两个步骤:第一是安排有经验的编程人员对代码进行走查和分析,找出内存泄漏发生的位置;第二是使用专门的内存泄漏测试工具进行测试. 第一个步骤: ...
- Java 技术篇-用java自带的内存检测工具排查内存泄漏问题,查看java垃圾回收情况,监控java堆内存变化
在 java 的 bin 文件夹下有个 jvisualvm.exe 工具,使用它可以检测到 java堆内存 的变化情况,借此可以来检测使用 java 的程序是否存在内存泄漏问题. 我们左边选择程序对应 ...
- android内存泄漏检测工具,Android内存泄漏的检测工具——LeakCanary
首先了解什么是内存泄露html http://liuwangshu.cn/application/performance/ram-3-memory-leak.htmlandroid 1Leakcanc ...
- qt内存泄漏检测_qt 关于内存泄漏的检测
Qt 关于内存泄露的检测: 工具篇关于Qt 内存泄露的检测工具有很多种,一下挑几种来说: 1.检测已分配资源, 第一个工具是一个内存资源使用的监听器.它只能在模拟器上进行调试.可以使用快捷键来调用 按 ...
- 【内存】内存检测工具sanitizer[内存泄漏、内存越界] VS valgrind
简介 Sanitizers是谷歌发起的开源工具集,包括了AddressSanitizer, MemorySanitizer, ThreadSanitizer, LeakSanitizer,Saniti ...
- 关于LeakCanary检测华为手机内存泄漏问题
手机华为:pra-al00,Android 8.0.0, 继承LeakCanary后,所有的activity均会爆出leaks, ...... references com.android.inter ...
- (转载)VC的内存泄漏检查
原文链接:https://blog.csdn.net/psbeond/article/details/99546363 日期: 2016-12-20 参考:MSDN:ms-help://MS.MSDN ...
- linux工具之检测内存泄漏-valgrind
0.前言 内存泄漏是c++程序常见的问题了,特别是服务类程序,当系统模块过多或者逻辑复杂后,很难通过代码看出内存泄漏: valgrind是一个开源的,检测c++程序内存泄漏有效工具,编译时加上-g选项 ...
- C++内存泄漏检测工具
C++内存泄漏检测工具 1.VC自带的CRT:_CrtCheckMemory 调试器和 CRT 调试堆函数 1.1用法: /************************************ ...
最新文章
- apache+svn服务搭建
- mysql 事件_区块链研究实验室 | 使用MySQL存储以太坊事件
- javascript中关于作用域和闭包
- html传递json中文乱码,解决后台传数据到前台中文乱码问题,使用@ResponseBody返回json 中文乱码...
- 关于C# Winform DataGridView 设置DefaultCellStyle无效的原因与解决方案
- 利用ASP .NET Core的静态文件原理实现远程访问Nlog日志内容及解决遇到的坑
- XML解析(二),DOM解析XML
- 在Python中使用Seaborn和WordCloud可视化YouTube视频
- select2,利用ajax高效查询大数据列表(可搜索、可分页)
- 更改npm淘宝源,并设置cnpm
- 計算機二級-java08
- Linux C基础笔记(4)终结篇
- 21天Jenkins打卡Day17-查看Jenkins服务器上的目录结构
- 【优化分类】基于matlab改进的人工蜂群算法优化SVM分类【含Matlab源码 1833期】
- android ios 录音功能,iOS与Android的音频互通
- 滴滴征战澳洲 全球“追击”优步
- 人体计算机原理,人体静力学
- 《东周列国志》第八十六回 吴起杀妻求将 驺忌鼓琴取相
- APIAuto——敏捷开发最强大易用的 HTTP 接口工具 (二)
- [转帖]全球软件市场格局变化
热门文章
- 2021大“游”不同——百度旅游行业洞察
- 2021年看得见的粉丝价值——五大平台KOL粉丝分析研究报告
- 互联网日报 | 网易严选宣布退出双十一大战;抖音企业号数量突破500万;大兴机场首推外卖直达登机口...
- lisp 发凹圆角_css能实现这样的内凹圆角吗?如何实现?具体代码是!!
- 2021年客户需求的新变化,带来了对程序员能力要求的新高度
- 专题导读:数据资产化探索
- 我刊成功承办第二届数据科学家大会(2018)
- 一本可能引发社会调查行业革命的书
- 【2017年第1期】大数据能力开放平台创新和发展
- 【编程语言】Ruby完全自学手册