今天着手解决一个现有程序的内存泄露问题,以前从没用过相关检测的工具、手段!
搜了几篇文章,感觉还不错:
主要的检测工具是debuger和crt堆除错函数:
http://bbs.17testing.com/viewthread.php?tid=8516 扫盲——内存泄漏的有关知识
http://leoman95.spaces.live.com/blog/cns!87f442ce8fa434b1!131.entry VC++6.0中内存泄漏检测
http://www.360doc.com/content/081028/22/7635_1840985.html vc内存泄露检测-常用技巧(转载)
http://fafeng.blogbus.com/logs/7525571.html 内存泄露检测工具
http://www.cppblog.com/bigsml/archive/2006/10/19/13860.html 用BoundChecker检测内存泄露(zz)
http://blueluhan.spaces.live.com/blog/cns!B0E40D35BB595164!1412.entry 使用BoundChecker的好处
【推荐】http://blog.youkuaiyun.com/seawen/archive/2009/01/05/3714128.aspx VC内存泄漏检测工具_Visual Leak Detector
推荐第三方内错泄露检测工具:
Purify 很好,很强大,收费
BoundsChecker 很好,很强大,收费
Visual Leak Detector 很好,很浅大,免费,源码都有,强烈推荐
这里主要介绍一下用法:
需在文件中包含以下
头文件和宏定义:
#include<stdlib.h>
#include<crtdbg.h>
#define _CRTDBG_MAP_ALLOC
环境:
打印的内存消息只在调试状态下,output窗口的debug页输出。
函数:
_CrtDumpMemoryLeaks(); 报告当前程序内存泄露状况
因为程序可能在多个出口,在main函数入口加上这句:
_CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );
即可保证,在程序结束时一定调用一次_CrtDumpMemoryLeaks();
_CrtMemState s1; 声明一个内存快照的结构体信息
_CrtMemCheckpoint( &s1 ); 将当前内存快照存储到s1中
_CrtMemDumpStatistics(&s1); 打印s1内存快照信息
_CrtMemDifference(&s3, &s1, &s2);将快照s1和s2的差异,存储到s3中
_crtBreakAlloc(45); 此函数用来在内存第45次分配时,产生中断,也可以在Watch窗口中,
name栏写“_crtBreakAlloc”, value值写“45”,同样会产生中断!便于调试!
注意:
在vc6.0下,若你的程序包含<iostream.h><string>等头文件,你会发现总是会报告内存泄露:
Detected memory leaks!
Dumping objects ->
{45} normal block at 0x00372638, 33 bytes long.
Data: < C > 00 43 00 CD CD CD CD CD CD CD CD CD CD CD CD CD
{44} normal block at 0x003725D0, 40 bytes long.
Data: < |L > 14 7C 4C 10 16 00 00 00 00 00 00 00 00 00 00 00
Object dump complete.
这估计是vc6的bug吧!
附上一个测试代码:
第三方工具VLD用法:visual leak detector
现在vld已经有了1.9的beta版,我用的是1.0版本,
1. 下载
解压后,会有:
三个lib文件,“vld.lib”,“vldmt.lib”,“vldmtdll.lib”
两个.h文件,“vld.h”,“vldapi.h”
一个dll文件,“dbhelp.dll”
2. 安装
把lib文件拷贝到vc6.0安装目录“.../Microsoft Visual Studio/VC98/Lib”下,
然后把.h文件拷贝到自己的工程目录下,
3. 使用
你工程的源码里,在程序入口文件处,第一个include那两个.h文件,若文件有“stdafx.h”,则
在include "stdafx.h"后,再包含两个文件。
4. 报告输出
vld是在调式状态下,才会进行内存检测,最终的报告也输出在output窗口的debug页。
对于非调试执行程序,vld不作任何检查,这样,及时发布程序,也无需注释掉vld,不影响性能!
5. 注意
若是发现报告内容都是地址码,没有函数名路径信息,则拷贝dbhelp.dll到工程的debug目录下即可!
附录:内存泄漏的发生方式(摘自: http://fafeng.blogbus.com/logs/7525571.html)
1.常发性内存泄漏。发生内存泄漏的代码会被多次执行到,每次被执行的时候都会导致一块内存泄漏。
2.偶发性内存泄漏。发生内存泄漏的代码只有在某些特定环境或操作过程下才会发生。常发性和偶发性是相对的。对于特定的环境,偶发性的也许就变成了常发性的。所以测试环境和测试方法对检测内存泄漏至关重要。
3.一次性内存泄漏。发生内存泄漏的代码只会被执行一次,或者由于算法上的缺陷,导致总会有一块且仅有一块内存发生泄漏。
4.隐式内存泄漏。程序在运行过程中不停的分配内存,但是直到结束的时候才释放内存。严格的说这里并没有发生内存泄漏,因为最终程序释放了所有申请的内存。但是对于一个服务器程序,需要运行几天,几周甚至几个月,不及时释放内存也可能导致最终耗尽系统的所有内存。所以,我们称这类内存泄漏为隐式内存泄漏。