C/C++内存管理之内存泄漏检查

一. 概述 内存泄漏一直是软件开发人员最头大的问题之一,尤其像C/C++这样自由度非常大的编程语言,几乎是每一个用其开发出来的软件都会出现内存泄漏的情况。 如果没有内存泄漏,世界或许会变的美好。然而,完全美好的世界是不存在的,我们能做的就是尽量让它变的更美好。 二. 工具介绍 纵观目前市面上有不少内存泄漏工具,在这里就不多做介绍。笔者最常用的是IBM公司出产的IBM Rational Purify,说起Purify这东西,稳定性虽然不怎么样,但功能很强大。它是IBM Rational PurifyPlus产品组中三剑客的一员。 Purify是面向C/C++, VB, Java语言,测试内存错误,Windows API访问错误,COM方法调用情况等。 图1. Purify主界面 Purify对于C/C++的分析支持源代码级,或通过其专利技术:“目标代码插入(Object Code Insertion)”工作在无源代码级。Purify的功能其实非常之强大,此次我们只讨论怎么通过Purify进行C/C++下的内存泄漏发现。在介绍它的工作流程前,我们来认识一下几个缩写术语的意思: l ABR: Array Bounds Read,数组越界读 l ABW:Array Bounds Write,数组越界写 l FMR:Free Memory Read,空间内存读取 l IPR: Invalid Pointer Read,无效指针读取 l IPW:Invalid Pointer Write,无效指针写入 l NPR:Null Pointer Read,空指针读取 l NPW:Null Pointer Write,空指针写入 l UMR:Uninitialized Memory Read,未初始化内存阅读 l MLK:Memory leaks,内存泄漏 l MIU:Memory in use, 内存使用中 l MPK:Potential memory leaks,潜在的内存泄漏 当我们完成了目标代码,生成可执行程序文件后,在Purify中加载它,便可自动完成可执行程序解析,运行,分析的一应工作。 图2. Rational Purify的工作流程 三. 泄漏场景及检测 现在,我们就来做几个案例,看看效果如何。开始之前,先介绍一下笔者的工作及测试环境: l Microsfot Windows XP Tablet PC Edition 2005 SP3 l 3G内存(再多的内存也怕泄漏J) l Microsfot Visual Studio 2005 l IBM Rational Purify 7.0 在这里想额外的说明一下,笔者曾经测试对比过VC2005和VC6生成程序,发现VC2005生成汇编代码质量比VC6的好很多,几乎接近人工编写。所以这就是为什么笔者不用VC6的原因。 好的,现在来编写一个超简单的内存泄漏例子,打开VS2005,新建一个标准的VC++控制台项目,输入如下例子,编译。 int _tmain(int argc, _TCHAR* argv[]) { int* i = new int(); // 内存在此申请后无释放,发生泄漏 *i = 10; printf("%d", *i); return 0; } 上面这段程序非常简单,在new完一个int实例后,却没有delete它。产生了一个4个字的内存泄漏。虽然简单,但还是来看看Rational Purify是怎么运作和发现它的吧: 首先,打开Purify,点击主菜单“File”,然后点击“Run…”,在弹出窗口(Run Program)中选中要测试的程序,最后点击按钮“Run”。至此,已完成程序加载步骤,Purify自动开始解析并运行程序。由于这是一个控制台应用程序,所以程序在输出一个10后便已完成,按任意键结束程序后,Purify便开始了自动分析并运行,一切都那么自然,那么简单。 J 图3. 加载程序并运行 图4. 例一分析报告窗口 果然,Purify没有让人失望的发现了程序的问题。现在,让我们再来试试复杂一点的,请看如下代码: int _tmain(int argc, _TCHAR* argv[]) { // 制造5个4个字节的内存泄漏 for (int i = 0; i < 5; ++i) { // 此处申请了1个4个字节的内存,但没有释放它 int* j = new int; *j = i; printf("%d", *j); } return 0; } 我们人为的制造了20个字节的内存泄漏,通过如上所述之步骤加载到Purify,运行结束如下图: 图5. 例二分析报告窗口 通过例二的分析,我们发现Purify也能正确的分析出内存泄漏的位置。最后,让我们来写一个类,在这个类里我们故意在构造函数里造成1个4个字节的内存泄漏,然后在main函数里new一个此类,不释放它,看看是什么效果,代码如下: class LeaksTest { public: LeaksTest() { // 此处申请了个个字节的内存,但没有释放 i = new int; *i = 1; } int geti() { return *i; } private: int* i; }; int _tmain(int argc, _TCHAR* argv[]) { // 此处new了一个LeaksTest对像,没有释放 LeaksTest* lt = new LeaksTest(); printf("%d", lt->geti()); return 0; } 还是老样子,编译完成后通过Purify来加载它,如图: 图6. 例三的分析报告窗口 四. 避免 在C/C++语言中,指针带给了人们非常大的灵活度,但它却是一把双刃剑,掌握不好却极易造成软件的内存问题,轻则出错,重则崩溃。 怎么有效的避免此类问题,目前比较有效的方法就是使用智能指针,所谓智能指针说白了就是用一个类把指针再封装起来以保证在这个封装类被释放时及时释放指针。但是要想非常完美的实现智能指针却是一件难度非常大的活。C++ STL就提供了一个智能指针,但功能却一般。正因为如此,BOOST库中也提供了智能指针类,为了应付不同情况下不同的需求,BOOST库提供了多个智能指针类,最大化了满足了这些要求。至于怎么使用这智能指针却不是这里要讲的内容了,读者如有兴趣可以自行去研究学习。 本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/ConserLin/archive/2008/09/01/2861978.aspx 分享 0 顶 阅读(280)┊ 评论 (0)┊收藏(0)┊转载┊顶▼┊ 打印┊举报已投稿到: 排行榜 圈子 加载中,请稍候...... 前一篇:学术圈内对IEEE和SCI等的简介后一篇:如何检查C++中的内存泄漏.评论重要提示:警惕虚假中奖信息,点击查看详情 关注每日最热门博客 [发评论]暂无评论。发评论关注每日最热门博客 订阅头条博客看明星隐私大腕焦点! 更多>>登录名: 密码: 找回密码 注册 记住登录状态建议在网吧/公用电脑上取消该选项 昵 称: 验证码: 请点击后输入验证码 收听验证码 评论并转载此博文 匿名评论发评论 以上网友发言只代表其个人观点,不代表新浪网的观点或立场。 新浪BLOG意见反馈留言板 不良信息反馈 电话:95105670 提示音后按2键(按当地市话标准计费) 欢迎批评指正 新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 会员注册 | 产品答疑 Copyright © 1996 - 2010 SINA Corporation, All Rights Reserved 新浪公司 版权所有 发照片 发视频 综合博文博主音乐视频播主 群组 最近顶了的博主:加载中… 为了您的账号安全,请绑定邮箱
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值