如何在.net应用中发现和避免内存泄露和资源泄露

关注51Testing
分享.net常见的内存泄露及解决方法
发表于: 09:59 &作者:狩月 & 来源:51Testing软件测试网采编
推荐标签:
  关于内存泄漏的问题,之前也为大家介绍过,比如:《》,是关于C++内存泄漏的。今天为大家介绍的是关于.NET内存泄漏的问题。  前段时间帮项目组内做了一次内存优化,产品是使用c#开发的winForm程序,一直以为.net提供了垃圾收集机制,开发的时候也没怎么注意内存的释放,导致最后的产品做出来之后,运行一个多小时就内存直接崩溃了,看来.net的垃圾收集还是得需要开发者加以控制,也不是万能的啊。  下面将对垃圾收集做以简介,然后描述一下我在内存优化过程中常见的内存泄露及解决方法。  托管堆的内存分配(下文中的托管堆指的是GC堆)  托管堆是以应用程序域为依托的,即每一个应用程序域有一个托管堆,每一个托管堆也只属于一个应用程序域,且托管堆是一块连续的内存,其中的对象也是紧密排列的。相对于C++中的非连续内存堆来说,托管堆的内存分配效率要高。托管堆维护了一个指针,指向当前已使用内存的末尾,当需要分配内存的时候,只需要指针向后移动指定数量的位置即可。而且托管堆通过应用程序域实现了应用程序之间内存的隔离,即不同的应用程序域之间在正常情况下是不能相互访问各自的托管堆的。  垃圾收集  垃圾收集的算法有很多。例如引用计数、标记清除等等,托管堆使用的标记清除算法。  托管堆使用的是分代标记清除算法。  标记清除算法  首先,系统将托管堆内所有的对象视为可以回收的垃圾,然后系统从GCRoot开始遍历托管堆内所有的对象,将遍历到的对象标记为可达对象,在遍历完成之后,回收所有的非可达对象,完成一遍垃圾收集。  注意,托管堆的垃圾收集只会自己收集托管对象!  由于在执行完垃圾收集之后,托管堆中会产生很多的内存碎片,导致内存不再连续,因此在垃圾收集完成之后,系统会执行一次内存压缩,将不连续的内存重新排列整齐,变成连续的内存。(关于垃圾收集的详细信息,大家可以参考《CLR Via C#》)  通过上面的简述,大家都知道什么样的对象不会被收集,即能从GCRoot开始遍历到的对象。  最常见的GCRoot是线程的栈,线程的栈里面通常包含方法的参数、临时变量等。另外常见的GCRoot还有静态字段、CPU寄存器以及LOH堆上的大的集合。因此,如果想要让托管对象的内存顺利的释放,只需要断开与跟之间的联系即可。而对于非托管对象的内存,必须进行手动释放。  下面我根据自己在优化内存的过场中的一些常见错误以及一些解决方法。  事件  在.net内存泄露的原因当中,事件占据了非常大的一部分比例,事件是一种委托的实例,也就是与我们类中的字段一样,也是一个字段。  委托为什么能阻止垃圾收集呢?即委托是如何让相关的对象在垃圾收集的时候被标记为可达对象的呢?首先要从委托的本质看起,  我们通常使用的委托是从类public&abstract&class&MulticastDelegate&:&Delegate  继承的,MulticastDelegate内部维护了一个private object _invocationList;,即我们通常所有的委托链(ps:委托链同字符串一样,是不可变的),这个委托链是以个object [],内部保存了Delegate对象,及每一个委托实际上是一个Delegate对象,而Delegate包含了两个非常重要的字段:internal&object&_ &internal&object&_methodB  其中_target就是订阅事件的对象,_methodBase则是订阅事件的方法的 MethodInfo。其关联关系如下例所示:Code: &public&event&EventHandler&TestE &void&MethodEndTempVarClear() &{ &Test&tempTestEvent&=&new&Test(); &TestEvent&+=&tempTestEvent.TestE &}
搜索风云榜
51Testing官方微信
51Testing官方微博
测试知识全知道批量和分页
  在典型的互联网web应用中,数据量较大且高并发的情况下,不分页,或者不进行批量处理,每次总是取出很多用户数据,很容易造成内存开销过大,系统内存吃紧。再比如我们有时候进行文件操作,读取文件内容的时候就要斟酌考虑文件有多大。
  比起大数据查询造成的常发性的内存不足,使用静态太多的应用程序一时半会也不会内存泄露。可随着系统的运行,静态的东西越来越多,内存开销也就越大,由于GC的回收策略,无效的静态所占内存又不容易及时释放,久而久之就造成了内存不足。
二方库、三方库,非托管资源,优先使用Dispose模式
  每次调用别人的资源都应该有个警觉性:用你的类库可以,占用我的(内存)不行。  如果你熟悉自动内存管理,熟悉GC,理解Dispose模式,那么一定会在调用别人的资源的时候想着还是using一下为妙,或者,强制赋个null也是举手之劳,要相信某些良好的编程习惯可以让自动内存管理更有效。
减少字符串临时对象
  举例来说,对于String的+=,很多应用程序中这个操作层出不穷。我们都知道+=操作会造成很多临时字符串对象,这些对象由于CLR对字符串的驻留处理,容易占用内存空间。如果是高并发的web应用程序,而字符串操作随处可见,且字符串的长度又不确定地长,前端页面各种各样的拼接,久而久之,内存占用就会是一个重大问题。CLR对字符串的优化处理使得字符串不被优先回收,如果字符串操作频繁,临时字符串较长(比如大于等于85000字节)而出现大对象堆的分配,那么更容易出现内存泄露。  很多人可能都会想到如何优化程序去降低string的临时对象的生成概率。对的,StringBuilder的出现就顺理成章了。
警惕大对象
  1、任何大于等于85000字节的对象都被自动视为大对象,大对象从特殊的大对象堆中分配。大对象堆和小对象堆一样进行终结和释放,但是GC回收算法从来不对大对象堆(Large Object Heap)进行内存压缩整理,因为在堆中下移85000字节或更大的内存块会浪费太多的CPU时间;  2、在.NET中,CLR采用基于代(generation)的垃圾回收,大对象总被认为是第2代(generation)的一部分,GC分析哪些对象不可达,优先分析第0代和第1代,第2代的对象通常被认为长时间存活。  正是由于1和2所述的两个原因(主要原因还是第1个),在垃圾回收过程中容易造成内存碎片。这里推荐一篇老外写的流传甚广的文章供参考:the dangers of the LOH。  随着应用程序的运行,如果LOH导致的内存碎片越来越多,内存有效使用率下降会非常严重,比如我们在web应用程序中+=拼接字符串(见第4条的分析),如果大于等于85000字节的字符串临时对象很多,那么用户量一上去,随着系统的运行,GC回收压力越来越大OOM的风险会变得更高。  虽然内存碎片化导致的OOM看上去似乎无解,但是如果写程序的人仔细分析解决问题,想方设法主动降低创建大对象的频率,那么内存泄露的可能就会降低,足够优秀健壮的程序不能彻底解决OOM,但是我们完全可以将风险发生的情况将至最低可能。  一个足够合格的coder肯定需要具备充足的分析和解决OOM问题的准备和经验,有很多分析和检查OOM的工具如ANTS Memory Profiler,还可以通过调试利器如windbg对内存dump文件进行分析。用好这些工具,让OOM无所遁形也不失为解决之道。
阅读(...) 评论()VS.NET中内存泄露问题的研究--《航天制造技术》2015年03期
VS.NET中内存泄露问题的研究
【摘要】:详细分析了.net中出现内存泄露的表现形式及可能途径,介绍了内存泄露的具体检测方法,以案例的形式重点描述了出现内存泄露问题时的处理方法。最后,针对不同的应用,提出了服务器程序性能优化方法,从不同角度提高了程序的效率与可靠性。
【作者单位】:
【关键词】:
【分类号】:TP333;TP309【正文快照】:
1引言 问题是非常隐蔽的问题,其表现形式是,刚开始程序运行良好,随着程序连续运行时间的增长,内存支出微软的.net框架是一个可以快速开发、部署web 越来越多,且不能正常释放,最后会导致程序崩溃,程序及windows程序的开发平台。它实现了多语言基 服务器卡死。服务器程序通常都
欢迎:、、)
支持CAJ、PDF文件格式,仅支持PDF格式
【参考文献】
中国期刊全文数据库
叶俊民;魏鹏;金聪;王敬华;张清国;张维;;[J];计算机科学;2010年06期
程振林;方金云;唐志敏;;[J];计算机工程;2007年04期
【共引文献】
中国期刊全文数据库
张云峰;赵逸智;;[J];北华航天工业学院学报;2011年06期
陈涛;许金超;钮俊;;[J];计算机工程与应用;2011年25期
孙凌宇;冷明;夏洁武;;[J];工矿自动化;2009年07期
王雅丽;李建良;;[J];计算机与现代化;2013年05期
中国博士学位论文全文数据库
姬秀娟;[D];南开大学;2014年
中国硕士学位论文全文数据库
许荣斌;[D];安徽大学;2007年
张伟;[D];北京邮电大学;2010年
王喆;[D];大连理工大学;2012年
高赛军;[D];华东理工大学;2013年
印玲;[D];华东理工大学;2015年
刘书文;[D];北京邮电大学;2015年
【二级参考文献】
中国期刊全文数据库
吴民,涂奉生;[J];计算机工程与应用;2005年14期
张广梅,李晓维;[J];计算机辅助设计与图形学学报;2005年03期
张威;卢庆龄;李梅;宫云战;;[J];计算机应用研究;2006年10期
【相似文献】
中国期刊全文数据库
雷达;曾庆凯;;[J];计算机应用研究;2011年11期
谢宇;宁艳文;;[J];程序员;2006年09期
汪小林;王振林;孙逸峰;刘毅;张彬彬;罗英伟;;[J];计算机学报;2010年03期
张德迪;;[J];科技信息;2006年08期
许丰宽;;[J];煤炭技术;2013年04期
张鹏;杨秋辉;李海怒;;[J];计算机工程与应用;2013年14期
杨光;;[J];信息与电脑(理论版);2010年07期
邵叶秦;;[J];电脑知识与技术(学术交流);2007年14期
蔡志强;丁丽萍;贺也平;;[J];计算机应用与软件;2012年09期
陈小玉;[J];微型电脑应用;2005年07期
中国重要会议论文全文数据库
许宝喜;王林章;;[A];全国第20届计算机技术与应用学术会议(CACIS·2009)暨全国第1届安全关键技术与应用学术会议论文集(下册)[C];2009年
中国重要报纸全文数据库
尼尔·麦卡利斯特;[N];中国计算机报;2010年
中国硕士学位论文全文数据库
陶淼;[D];对外经济贸易大学;2007年
&快捷付款方式
&订购知网充值卡
400-819-9993
《中国学术期刊(光盘版)》电子杂志社有限公司
同方知网数字出版技术股份有限公司
地址:北京清华大学 84-48信箱 大众知识服务
出版物经营许可证 新出发京批字第直0595号
订购热线:400-819-82499
服务热线:010--
在线咨询:
传真:010-
京公网安备75号分类/内存泄露
内存泄露以发生的方式来分类,内存泄漏可以分为4类:
发生内存泄漏的代码会被多次执行到,每次被执行的时候都会导致一块内存泄漏。
发生内存泄漏的代码只有在某些特定环境或操作过程下才会发生。常发性和偶发性是相对的。对于特定的环境,偶发性的也许就变成了常发性的。所以测试环境和测试方法对检测内存泄漏至关重要。
发生内存泄漏的代码只会被执行一次,或者由于算法上的缺陷,导致总会有一块且仅一块内存发生泄漏。比如,在类的构造函数中分配内存,在析构函数中却没有释放该内存,所以内存泄漏只会发生一次。
程序在运行过程中不停的分配内存,但是直到结束的时候才释放内存。严格的说这里并没有发生内存泄漏,因为最终程序释放了所有申请的内存。但是对于一个服务器程序,需要运行几天、几周甚至几个月,不及时释放内存也可能导致最终耗尽系统的所有内存。所以,我们称这类内存泄漏为隐式内存泄漏。
危害/内存泄露
从用户使用程序的角度来看,内存泄漏本身不会产生什么危害,作为一般的用户,根本感觉不到内存泄漏的存在。真正有危害的是内存泄漏的堆积,这会最终消耗尽系统所有的内存。从这个角度来说,一次性内存泄漏并没有什么危害,因为它不会堆积,而隐式内存泄漏危害性则非常大,因为较之于常发性和偶发性内存泄漏它更难被检测到。
表现/内存泄露
内存泄露cpu资源耗尽:估计是机器没有反应了,键盘,,以及网络等等。这个在windows上经常看见,特别是中了毒。进程id耗尽:没法创建新的进程了,串口或者telnet都没法创建了。硬盘耗尽:&机器要死了,交换没法用,日志也没法用了,死是很正常的。内存泄漏或者内存耗尽:新的连接无法创建,free的内存比较少。发生内存泄漏的程序很多,但是要想产生一定的后果,就需要这个进程是无限循环的,是个服务进程。当然,内核也是无限循环的,所以,如果内核发生了内存泄漏,情况就更加不妙。内存泄漏是一种很难定位和跟踪的,目前还没看到有什么好用的工具(当然,用户空间有一些工具,有静态分析的,也会动态分析的,但是找内核的内存泄漏,没有好的开源工具)。内存泄漏和对象的引用计数有很大的关系,再加上c/c++都没有自动的垃圾回收机制,如果没有手动释放内存,问题就会出现。如果要避免这个问题,还是要从代码上入手,良好的编码习惯和规范,是避免错误的不二法门。一般我们常说的内存泄漏是指堆内存的泄漏。堆内存是指程序从堆中分配的,大小任意的(内存块的大小可以在程序运行期决定),使用完后必须显式释放的内存。应用程序一般使用malloc,realloc,new等从堆中分配到一块内存,使用完后,程序必须负责相应的调用free或delete释放该内存块,,这块内存就不能被再次,我们就说这块内存泄漏了。
检测工具/内存泄露
内存泄露部分工具1.ccmalloc-Linux和Solaris下对C和C++程序的简单的使用和malloc调试库。
2.Dmalloc-Debug&Malloc&Library.
3.Electric&Fence-Linux分发版中由Bruce&Perens的malloc调试库。
4.Leaky-Linux下检测内存泄漏的程序。
5.LeakTracer-Linux、Solaris和HP-UX下跟踪和分析C++程序中的内存泄漏。
6.MEMWATCH-由Johan&Lindh编写,是一个开放源代码C语言内存错误检测工具,主要是通过gcc的precessor来进行。7.Valgrind - Debugging&and&profiling&Linux&programs,&aiming&at&programs&written&in&C&and&C++.
8.KCachegrind-A&visualization&tool&for&the&profiling&data&generated&by&Cachegrind&and&Calltree.
9.IBM&Rational&PurifyPlus-帮助开发人员查明C/C++、托管.NET、Java和VB6代码中的性能和可靠性错误。PurifyPlus&将内存错误和、应用程序性能描述、覆盖分析等功能组合在一个单一、完整的工具包中。 10.ParasoftInsure++-针对C/C++应用的运行时错误自动检测工具,它能够自动监测C/C++程序,发现其中存在着的内存破坏、内存泄漏、指针错误和I/O等错误。并通过使用一系列独特的技术(SCI技术和变异测试等),彻底的检查和测试我们的代码,精确定位错误的准确位置并给出详细的诊断信息。能作为MicrosoftVisual&C++的一个插件运行。11.Compuware&DevPartner&for&Visual&C++&BoundsChecker&Suite-为C++开发者设计的运行错误检测和调试工具软件。作为Microsoft&Visual&Studio和C++&6.0的一个插件运行。12.Electric&Software&GlowCode-内存泄漏检查,code&profiler,函数调用跟踪等功能。给C++和.Net开发者提供完整的错误诊断,和运行时性能分析工具包。
13.Compuware&DevPartner&Java&Edition-包含Java内存检测,代码覆盖率测试,代码性能测试,线程死锁,分布式应用等几大功能模块。
14.Quest&JProbe-分析Java的内存泄漏。
15.ej-technologies&JProfiler-一个全功能的Java剖析工具,专用于分析J2SE和J2EE应用程序。它把CPU、执行绪和内存的剖析组合在一个强大的应用中。
16.BEAJRockit-用来诊断Java内存泄漏并指出根本原因,专门针对Intel平台并得到优化,能在Intel硬件上获得最高的性能。
&|&相关影像
互动百科的词条(含所附图片)系由网友上传,如果涉嫌侵权,请与客服联系,我们将按照法律之相关规定及时进行处理。未经许可,禁止商业网站等复制、抓取本站内容;合理使用者,请注明来源于。
登录后使用互动百科的服务,将会得到个性化的提示和帮助,还有机会和专业认证智愿者沟通。
此词条还可添加&
编辑次数:15次
参与编辑人数:7位
最近更新时间: 13:34:06
认领可获得以下专属权利:
贡献光荣榜}

我要回帖

更多关于 如何避免内存泄露 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信