Chinaunix首页 | 论坛 | 博客
  • 博客访问: 83355
  • 博文数量: 9
  • 博客积分: 187
  • 博客等级: 入伍新兵
  • 技术积分: 121
  • 用 户 组: 普通用户
  • 注册时间: 2011-03-06 22:38
个人简介

网络设备制造商硬件打杂店小二

文章分类

全部博文(9)

文章存档

2016年(2)

2012年(1)

2011年(6)

我的朋友

分类: C/C++

2011-05-13 18:09:46

        PCIe应用程序调试时,发现程序出现内存泄露,经过自己的摸索,以及向软件同学请教,最终解决了此问题。

1. 现象描述

应用程序开发环境为VC++,运用其debug功能进行单步调试时,程序总是报出内存泄露的错误,报告内容如下所示:

--------------------------------------------------------------------------------------------------------------------

Detected memory leaks!

Dumping objects ->

strcore.cpp(118) : {143} normal block at 0x009A3E60, 53 bytes long.

 Data: <    (   (   F:\p> 01 00 00 00 28 00 00 00 28 00 00 00 46 3A 5C 70

Object dump complete.

The thread 0x9BC has exited with code 0 (0x0).

The program 'F:\program\SP5301\SP5301GUI\Debug\SP5301GUI.exe' has exited with code 0 (0x0).

--------------------------------------------------------------------------------------------------------------------

经过网上查阅相关资料,得知报告中相关参数含义如下:

118:内存泄露的位置在strcore.cpp中第118

143:内存分配编号。 内存可能是在多次分配之后才出现泄露。
   
normal block块类型为普通型。
   
0x009A3E60内存位置。
   
53 bytes long块大小为53字节。
   
第四行显示前 16 字节的内容为“< ( (F:\p> 01 00 00 00 28 00 00 00 28 00 00 00 46 3A 5C 70

第五行显示内存泄露的线程,以及返回值。

2. 调试过程

虽然报告中显示内存泄露的位置在strcore.cpp中第118行。但是,此文件不在我的工程文件中。那么它应该是在程序运行时被调用过。而且它可能被多次调用。到底是哪次调用时出现的内存泄露,我们不得而知。为了解决内存泄露问题,准确定位内存泄露的位置是关键。

首先进入单步调试,然后打开VC++菜单中view->debug windows->Memory。通过报告中给出的内存地址0x009A3E60,查看该地址存储的内容为"F:\program\SP5301\s6_tfg484_pcie\testdata.txt"。结合程序内容,我猜测此字符串应该为我定义的字符串指针filepath。打开watch窗口,查看filepath的值,发现果然与上面看到的一致。于是定位了内存泄露的位置为filepath变量。

此字符串指针最初是在一个类里面定义的。最后赋给它的值是一个文件的路径。怀疑是该指针最后没有成功释放才导致的内存泄露。于是,我将filepath从类里面移出来,放在函数里面作为局部变量来定义。最终解决了内存泄露问题。

3. 归纳总结

发生内存错误是件非常麻烦的事情。编译器不能自动发现这些错误,通常是在程序运行时才能捕捉到。而这些错误大多没有明显的症状,时隐时现,增加了改错的难度。

常见的内存错误及其对策如下:

(1)      内存分配未成功,却使用了它。

编程新手常犯这种错误,因为他们没有意识到内存分配会不成功。常用解决办法是,在使用内存之前检查指针是否为NULL。如果指针p是函数的参数,那么在函数的入口处用assert(p!=NULL)进行检查。如果是用mallocnew来申请内存,应该用if(p==NULL) if(p!=NULL)进行防错处理。

(2)      内存分配虽然成功,但是尚未初始化就引用它。

犯这种错误主要有两个起因:一是没有初始化的观念;二是误以为内存的缺省初值全为零,导致引用初值错误(例如数组)。 内存的缺省初值究竟是什么并没有统一的标准,尽管有些时候为零值,我们宁可信其无不可信其有。所以无论用何种方式创建数组,都别忘了赋初值,即便是赋零值也不可省略,不要嫌麻烦。

(3)      内存分配成功并且已经初始化,但操作越过了内存的边界。

例如在使用数组时经常发生下标“多1”或者“少1的操作。特别是在for循环语句中,循环次数很容易搞错,导致数组操作越界。

(4)      忘记了释放内存,造成内存泄露。

含有这种错误的函数每被调用一次就丢失一块内存。刚开始时系统的内存充足,你看不到错误。终有一次程序突然死掉,系统出现提示:内存耗尽。

动态内存的申请与释放必须配对,程序中mallocfree的使用次数一定要相同,否则肯定有错误(new/delete同理)。

(5)      释放了内存却继续使用它。

有三种情况:

A.        程序中的对象调用关系过于复杂,实在难以搞清楚某个对象究竟是否已经释放了内存,此时应该重新设计数据结构,从根本上解决对象管理的混乱局面。

B.        函数的return语句写错了,注意不要返回指向“栈内存”的“指针”或者“引用”,因为该内存在函数体结束时被自动销毁。

C.        使用freedelete释放了内存后,没有将指针设置为NULL。导致产生“野指针”。

阅读(11011) | 评论(0) | 转发(0) |
1

上一篇:Windows驱动开发工具小结

下一篇:强大的gdb

给主人留下些什么吧!~~