扫盲————内存泄漏的有关知识

上一篇 / 下一篇  2007-08-28 12:46:42 / 个人分类:LR

查看( 2324 ) / 评论( 20 )
有关内存泄漏的知识
最近在看LR,对于内存泄漏的知识有点模糊,查找的有关资料,跟大家分享,本文只是介绍了内存泄漏的概念,例子,分类,表现,和检测方法,抛砖引玉,希望大侠们能分享自己检测出的内存泄漏实例
1.概念
简单的说就是你申请了一块内存空间,使用完毕后没有释放掉。它的一般表现方式是程序运行时间越长,占用内存越多,最终用尽全部内存,整个系统崩溃。由程序申请的一块内存,且没有任何一个指针指向它,那么这块内存就泄露了。
2.泄漏的例子
举几个例子   
  void   fun0()   
  {   
      char   *p=new   char[100];   
  }   
  执行完上面的函数就发生了泄露   
  指针p是局部变量,函数执行完后,指针p被销毁,造成   new   char[100]的内存没有指针指向它   
  ,也就无法再使用,造成内存泄漏。  
  void   fun1()   
  {   
      char   *p=new   char[100];   
      p=new   char[100];   
  }   
  这也泄露了   
   
  void   fun2()   
  {   
      new   char[100];   
  }   
  这东西肯定泄露完了   
   
  void   fun3(char   *a)   
  {   
      char   *p=new   char[100];   
      char   *b=p;   
      p=a;   
      a=b;   
  }   
  可能有泄露,赶紧去加内存条。
3.泄漏的分类
以发生的方式来分类,内存泄漏可以分为4类:

1. 常发性内存泄漏。发生内存泄漏的代码会被多次执行到,每次被执行的时候都会导致一块内存泄漏。
2. 偶发性内存泄漏。发生内存泄漏的代码只有在某些特定环境或操作过程下才会发生。常发性和偶发性是相对的。对于特定的环境,偶发性的也许就变成了常发性的。所以测试环境和测试方法对检测内存泄漏至关重要。
3. 一次性内存泄漏。发生内存泄漏的代码只会被执行一次,或者由于算法上的缺陷,导致总会有一块仅且一块内存发生泄漏。比如,在类的构造函数中分配内存,在析构函数中却没有释放该内存,所以内存泄漏只会发生一次。
4. 隐式内存泄漏。程序在运行过程中不停的分配内存,但是直到结束的时候才释放内存。严格的说这里并没有发生内存泄漏,因为最终程序释放了所有申请的内存。但是对于一个服务器程序,需要运行几天,几周甚至几个月,不及时释放内存也可能导致最终耗尽系统的所有内存。所以,我们称这类内存泄漏为隐式内存泄漏。

从用户使用程序的角度来看,内存泄漏本身不会产生什么危害,作为一般的用户,根本感觉不到内存泄漏的存在。真正有危害的是内存泄漏的堆积,这会最终消耗尽系统所有的内存。从这个角度来说,一次性内存泄漏并没有什么危害,因为它不会堆积,而隐式内存泄漏危害性则非常大,因为较之于常发性和偶发性内存泄漏它更难被检测到。
4.内存泄漏的表现
内存泄漏或者是说,资源耗尽后,系统会表现出什么现象哪?
cpu资源耗尽:估计是机器没有反应了,键盘,鼠标,以及网络等等。这个在windows上经常看见,特别是中了毒。
进程id耗尽:没法创建新的进程了,串口或者telnet都没法创建了。
硬盘耗尽: 机器要死了,交换内存没法用,日志也没法用了,死是很正常的。
内存泄漏或者内存耗尽:新的连接无法创建,free的内存比较少。发生内存泄漏的程序很多,但是要想产生一定的后果,就需要这个进程是无限循环的,是个服务进程。当然,内核也是无限循环的,所以,如果内核发生了内存泄漏,情况就更加不妙。内存泄漏是一种很难定位和跟踪的错误,目前还没看到有什么好用的工具(当然,用户空间有一些工具,有静态分析的,也会动态分析的,但是找内核的内存泄漏,没有好的开源工具)
内存泄漏和对象的引用计数有很大的关系,再加上c/c++都没有自动的垃圾回收机制,如果没有手动释放内存,问题就会出现。如果要避免这个问题,还是要从代码上入手,良好的编码习惯和规范,是避免错误的不二法门。
5.内存泄漏的检测
内存泄漏检测工具介绍:http://bbs.51testing.com/thread-87138-1-1.html,只是列出了各个工具,具体实践没有
另外网上还有很多针对java和c++等的内存泄漏的文章
Java内存泄漏:http://www.blogjava.net/galaxyp/archive/2006/04/28/43724.html
VC6.0内存泄漏检测:http://leoman95.spaces.live.com/blog/cns!87f442ce8fa434b1!131.entry
LR中:如果Process\Private Bytes计数器和Process\Working Set计数器的值持续升高,同时Memory\Available bytes计数器的值却持续降低的话,说明很有可能是存在内存泄漏

TAG: LR

Smoke中转站 shanxi 发布于2007-08-17 11:26:45
不错

建议由条件的 去看 “C++内存管理”。
b47617发布于2007-08-17 11:48:28
泄漏的分类,不错.
suoyi发布于2007-08-17 12:46:47
顶一下~~
受教了~~
hhy0824发布于2007-08-17 12:46:51
en  ,明白了很多
alextowxm的个人空间 alextowxm 发布于2007-08-17 13:28:46
谢谢
Ramon22的Blog Ramon22 发布于2007-08-17 13:59:48
学习了。
zzy9zzy5发布于2007-08-17 14:06:23
把C++学一遍,全解决了。new和delete要成对书写,指针用完了别忘了释放,按规矩来写程序一般不会泄露的。
aliren发布于2007-08-17 14:15:09
写的不错,赞一个
423799223发布于2007-08-17 14:21:43
楼主总结的好
呵呵
谢谢
iyoyo发布于2007-08-17 15:01:30
学习了。谢谢!
dandan的个人空间 dandan 发布于2007-08-17 15:58:49
不错,先保存了,以后继续看......
nutmeat发布于2007-08-19 15:40:32
学习
学习学习学习
luofeng发布于2007-08-20 10:05:11
学习
hadywei发布于2007-08-21 09:53:50
对内存泄露有了进一步的认识,谢谢lz拉

想请教一下,用lr测试性能时,如果吞吐量曲线没有显著的变化,在一定时期内保持稳定,而内存值曲线却始终持续增加,是否可以说明是内存泄露的表现呢?

还有能否再介绍下内存泄露和资源泄露的区别呢?
Smoke中转站 shanxi 发布于2007-08-21 10:59:26
什么是系统资源?
当应用程序在Windows中运行时,Windows必须实时"跟踪"该应用程序的运行,并保留与之相关的许多信息,如按钮、光标、菜单的位置和位图、窗口的状况等,这些信息由Windows保留在一种叫堆的内存块中,堆的英文为Heap。简单地说,堆是采用特殊机制管理的内存块。由Windows的一个系统内核User.exe管理的堆叫作User资源堆(User Resource Heap),由另一个系统内核Gdi.exe管理的堆叫作GDI资源堆(Graphical Device Interface Resource Heap,简称GDI Resource Heap),User资源堆和GDI资源堆合称为系统资源堆(System Resource Heap),习惯上就把它们叫作系统资源(System Resource)。
  微软将Windows的系统资源(堆)分为五个堆,其中User资源堆为三个,而GDI资源堆为两个。
  三个User资源堆分别是:16位的用户堆(User Heap,64KB);32位的窗口堆(Windows Heap,2MB);32位的用户菜单堆(User Menu Heap,2MB)。
  两个GDI资源堆分别是:16位的GDI堆(GDI Heap,64KB);32位的GDI堆(GDI,2MB)。
  从这里的系统资源分类和大小我们应该明白,不管CPU是P4还是486,内存是8M还是1G,所有Windows的用户都拥有同样大小的系统资源(堆),用户不能自己增加或减少系统资源的大小,这是由操作系统决定的,与硬件档次没有任何关系。
  Windows的User资源堆和GDI资源堆的可用(Free)空间称为可用 User资源和可用GDI资源,Windows中以百分数表示它们,用户可以选择 "开始/附件/系统工具/系统信息",来实时查看它们的大小。

什么情况下可能产生资源泄漏?
  比如一个程序还未完成其加载过程时(即还没有启动完毕)就关闭它会造成资源泄漏,而且只有重新启动才能回收。
  另外一些应用程序退出后Windows并不马上收回分配给它的系统资源,而是保持15分钟左右,到Windows完全肯定不再需要时才将它们收回,这可以看作是延时初始化的一种延伸。
  用户使用"Ctrl+Alt+Del"强制性地关闭一些应用程序会造成资源泄漏,因此用户应该尽量使用应用程序本身的关闭功能退出应用程序,只有实在没办法时才使用这种关闭方法。因为这种强制关闭应用程序的方法往往只能关闭主程序,而不能关闭应用程序的一些子程序,因此会导致一些系统资源发生泄漏。
  一些编写不善的应用程序会造成资源泄漏。一个应用程序在运行中往往会因出现意外而崩溃,若程序员在编写应用程序时没有考虑到这种意外情况的出现,并在应用程序中有相应的代码处理这种意外,那么当该应用程序非正常关闭后,该应用程序所占用的系统资源就不能由Windows收回。
  还有一些应用程序,即使是正常关闭也不会释放它所占用的系统资源,这样的应用程序被程序员称为"垃圾",计算机用户绝对不要使用这样的软件。
  还有一些实际存在而微软也没有给予解释的情况。比如用户上网结束后关闭拨号网络中的网络连接,然后按Ctrl+Alt+Del看看,一定会发现有一个名为rnaap(英文版)或者rnaapp(中文版)的程序还在运行,这是什么东西?其实这是拨号网络用来拨通ISP的远程网络访问程序(Remote Network Access Application Program),在用户登录网络的时候这个程序被运行,但是在用户从网络注销后它本身并未退出。这不免让人产生这样一个疑问:在这样一个庞大的Windows系统中,到底还有多少这样那样的例外存在呢?

对策
  1.准确地来讲,Windows中并不存在一个有着实际意义的系统资源。可用系统资源一定等于可用User资源和可用GDI资源中值较小的那一个。
  2.Windows的可用User资源是根据所有User资源堆中可用空间最小的那个资源堆计算出来的;可用GDI资源的计算方法也是一样。为了保持与16位应用程序的兼容性, Windows 9X的大量数据都要使用16位64KB资源堆,这导致总是16位64KB的资源堆首先被大量消耗,因此在 Windows 9X中,限制系统资源使用的是64KB的资源堆而不是2MB的资源堆。
  3.系统资源是用来跟踪应用程序的运行而不是用来运行应用程序的,就像公路上车多车少,并不是车稍微多点就没有办法开车了。因此可以肯定地说,影响计算机系统性能的是计算机系统其他的因素,而绝不会是可用系统资源的大小。当用户计算机系统性能明显降低时,应该从别的方面去查找原因,而不要马上怀疑到系统资源身上。从硬件方面来看, 内存太小导致系统不得不频繁使用虚拟内存是影响系统性能的主要原因之一;从软件方面来看,因为Windows是一个多任务的操作系统,大家都习惯同时运行多个应用程序而不管当时是否实际需要。而编写和调试这些应用程序的程序员一般只考虑其在单任务环境下的运行,而没有过多的精力从多任务环境来考虑和调试,因此许多应用程序间往往不能很好地协同工作,同时运行多个这样的应用程序会因它们彼此之间发生冲突而导致系统性能下降。当然,Windows 9X多任务管理机制的不完善也是造成这个问题的主要原因之一。
  4.虽然可用系统资源的减少不会对系统的性能有任何影响,但是其值最好不要小于10%,小于此值带来的直接后果是可能不能再加载新的应用程序,而副作用是系统崩溃的可能性大大增加。
  5.Windows本身也要占用系统资源,因此绝对没有哪个Windows用户的可用系统资源会是百分之百,要保持有更多的可用系统资源的方法是不要同时运行太多的应用程序。Windows和它的许多应用程序都有一个不经用户同意就自动加载东西的坏毛病,大家可以运行Msconfig.exe来关闭一些没有必要自动加载的应用程序,如ICQ、电子词典和超级解霸的自动播放伺服器等。
  6.不要将系统资源和CPU资源(CPU使用率)相混淆,硬盘、光驱、软猫的数据处理、显卡的3D图像处理、声卡的3D音效处理占用的都是CPU时间(即消耗CPU资源),而不是系统资源,这些硬件设备的先进与否与占用系统资源的多少根本没有任何关系,可至今许多人还是将它们混为一谈。按习惯,谈到硬件的资源占用一般是指其CPU资源的占用,而软件的资源占用既包括CPU资源占用又包括系统资源(堆)占用,但计算机用户关心的一般是后者,因此谈到软件的资源占用时一般是指其对系统资源的占用。

[ 本帖最后由 shanxi 于 2007-8-21 11:02 编辑 ]
游过去就是岸 zhsh1203 发布于2007-08-21 12:07:58
学习
学习学习学习
my_test的个人空间 my_test 发布于2007-08-29 17:21:09
我看看。
harneyluo的个人空间 harneyluo 发布于2007-08-30 11:19:22
学习了,谢谢
heyy2008的个人空间 heyy2008 发布于2007-08-31 12:58:41
呵呵,正好了解这这方面等内容,谢谢了,收藏
sgl_happy的个人空间 sgl_happy 发布于2007-08-31 16:42:25
学习了,谢谢!
我来说两句

(可选)

Open Toolbar