内存泄漏的跟踪和解决办法

再次抱怨下:编写C++程序,最烦人的事情就是对象的内存管理工作。好不容易把内存访问冲突问题搞定,又跑出内存泄漏一渣。

 

幸运的是,C++的IDE会帮我们找出程序的内存泄漏。不幸的是,IDE老是在程序退出调试时提醒我们找到内存泄漏,无形中给我们极大的压力。苦笑一下。

 

看了很多资料(包括MSDN),都说要添加下面的语句,在调试时才能输出内存泄漏信息:

 

事实上,在VS2005上,不用对项目做任何额外的设置,也不用添加上面提到的代码,在程序调试的退出时,默认即会在输出框输出内存泄漏信息。如:

 

VS能检查的内存泄漏有两类,第一类是知道内存分配代码的位置,双击即可定位;第二类不能定位代码,只给出内存分配块号(编号),如上面的“{9878}”

 

如果根据块号找到对应的内存分配(new)代码呢?可以使用一个C运行时环境变量(_crtBreakAlloc),在内存分配编号上设置断点。即调试项目(F5),在系统分配指定块号的内存时,调试器将触发一个断点,位置在分配代码上。此时可以跟踪其堆栈信息,分析内存泄漏的原因。

 

内存分配编号上设置断点的方法是:

1. 根据调试信息得到某一泄漏内存块的编号。

2. 在程序启动时(确保分配指定内存块之前),给_crtBreakAlloc赋值为内存编号,如:_crtBreakAlloc=9878;

3. 再次调试运行,程序将在指定的内存块分配时中断。

 

注意:并不是所有泄漏块号都能用这种方法定位。只有在内存块号固定时(每次调试,泄漏块号都相同),这种方法才有效。

 

OK,找到内存泄漏位置之后,接下来就是找出泄漏的原因,并解决它!

 

这里列出几种常见的引起内存泄漏的场合,以供参考:(按泄漏对象的可视范围划分)

 

1. 函数栈级对象:在函数内,暂时申请了一块内存(没有赋给类成员指针或全局指针,如临时缓冲),但没有释放它。这种情况最简单,

容易解决,在用完后释放即可。

 

2. 类级规则对象:在构造函数中分配,在普通成员函数中访问,但在析构函数中忘记释放。这种情况也简单,析构函数中释放它即可。如果在类编写时就注意到这点,那么这类泄漏一般可以避免。

 

3. 类级非规则对象:在构造函数中没有分配,只是简单初始化为NULL;对象分配推迟到普通的成员函数(可能是节省内存考虑);在析构函数中安全释放对象。所谓安全释放,是这样一种调用形式:判断指针是否为空,如果非空,则释放它,然后复位指针为空,即COM中的宏SAFE_DELETE(p)。可以看出,这种对象管理形式一般能很好地工作,但中间环节不能有任何遗漏。忽略了一环,就可能出现泄漏。这里重点说一下对象分配所在的普通成员函数,暂时称之为对象分配函数吧。这个函数可能被客户代码调用多次,因此在为对象分配内存前,请先安全释放它;或者使用机制确保分配代码只会被执行一次,怎么解决取决于类的设计思想。

 

4. 类外级包络对象:在分析泄漏时,如果排除了类内可能出现的泄漏(通常是类设计缺陷),但目标泄漏仍然出现,是时候检查该类的客户代码了。很有可能,组合了泄漏对象的对象本身也没有释放,而且可以继续往上回朔。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值