科技行者

行者学院 转型私董会 科技行者专题报道 网红大战科技行者

知识库

知识库 安全导航

至顶网软件频道应用软件Visual C 中检测和隔离内存泄漏

Visual C 中检测和隔离内存泄漏

  • 扫一扫
    分享文章到微信

  • 扫一扫
    关注官方公众号
    至顶头条

具有动态的分配和释放内存的能力是C/C 程序语言的重要特色之一。VisualC debugger和CRT库提供了一系列有效的检测和鉴定内存泄漏的工具。

作者:教程网 来源:教程网 2007年9月14日

关键字: 软件

  • 评论
  • 分享微博
  • 分享邮件
在内存分配数目处设置一个断点

在内存泄漏报告中的文件名和行号可告诉分配泄漏的内存的代码位置,但是光是有这些信息对于完整了解泄漏原因,有时候还是不够的。因为一个程序在运行时,一段分配分配内存的代码将会被调用很多次,但可能是某次调用后没有释放内存而导致了泄漏内存。为了确定是那些内存没有被释放,你必须不仅要知道泄漏的内存在那里被分配,还要知道泄漏产生的条件。对你来说,有帮助的信息就是内存分配号——在文件名和行号之后的花括号对中出现的数值。

例如,在下面的输出信息中,"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个对象(在大部分情况下,它都不会是。)

这样的话,你可以利用分配号在内存分配的地方设置一个断点。为了设置这样一个端点,你可以在你的程序开始处,设置一个位置断点。当你的程序在那一点break时,你就能够从QuickWatch对话框或者Watch窗口设置这样一个位置断点。

例如,在Watch窗口中,在Name栏键入下面的表达式:

_crtBreakAlloc


如果你正在用CRT库dynamic-link library (DLL)的多线程版本,你必须含有上下文操作符,像这样:

{,,msvcrtd.dll}_crtBreakAlloc


现在按下RETURN键,调试器找到该值并把结果放置在value栏。如果你在内存分配过程中还没有设置任何内存分配断点,那么这个值是-1。用你想要去中断的内存分配的分配数值来,取代value表中的值——例如,18。

当设置完内存分配断点之后,继续调试。这时,运行程序时一定要小心,要保证内存块分配的顺序不会改变。当你的程序在内存分配点中断的时候,你就能够查看Call Stack窗口和其他的DEBUG信息来分析泄漏原因了。你仍然可以继续从那一点执行程序,以至于了解到底发生了什么,同时确定为什么内存没有被释放(设置一个内存分配断点是很有帮助的)。

虽然在调试器中设置内存分配断点通常更容易,但是如果你喜欢的话,你也可以在你的代码中设置它们。为了在你的代码中设置一个内存分配断点,可以增加这样一行(对于第十八个内存分配):

_crtBreakAlloc = 18;


你还有可以使用有相同效果的_CrtSetBreakAlloc函数:

_CrtSetBreakAlloc(18);


比较内存状态

定位内存泄漏的另一个方法就是在关键点对应用程序的内存状态做快照。CRT库提供了一个结构类型_CrtMemState。你可以用它来存储内存状态的一个快照:

_CrtMemState s1, s2, s3;


为了在特定点对内存状态进行快照,可以传递一个_CrtMemState结构到he _CrtMemCheckpoint函数。此函数用当时内存状态的一个快照来填充此结构:

_CrtMemCheckpoint( &s1 );


你可以通过传递此结构到_CrtMemDumpStatistics函数来dump _CrtMemState结构的任意点的内容:

_CrtMemDumpStatistics( &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来定位泄漏。

查看本文来源

    • 评论
    • 分享微博
    • 分享邮件
    邮件订阅

    如果您非常迫切的想了解IT领域最新产品与技术信息,那么订阅至顶网技术邮件将是您的最佳途径之一。

    重磅专题
    往期文章
    最新文章