请任何人都可以推荐快速检查清单/最佳实践指南,以帮助我们避免在.net应用程序中导致内存泄漏的简单(但微妙)错误
当我处于项目的测试阶段时,我发现开始寻找内存泄漏的原因很困难而且非常痛苦.
如果有"经验法则"来完全指导托管应用程序中的内存泄漏,我恳请您分享您的经验.
谢谢.
(我认为托管应用程序被假定为'内存管理'即GC?为什么我们仍然会在纯托管代码中发现泄漏?)
有许多形式的泄漏:
非托管泄漏(分配非托管代码的代码)
资源泄漏(分配和使用非托管资源的代码,如文件,套接字)
延长对象的使用寿命
错误理解GC和.NET内存管理的工作原理
.NET运行时中的错误
前两个通常由两个不同的代码处理:
在对象上实现IDisposable并在Dispose方法中处理非托管内存/资源
实现终结器,以确保在GC发现对象符合收集条件时取消分配非托管资源
然而,第三个是不同的.
假设您正在使用包含数千个对象的大型列表,总计相当大的内存.如果您对此列表的引用保留的时间超过了您的需要,那么您将看起来像内存泄漏.此外,如果您继续添加到此列表中,以便它定期生成更多数据,并且永远不会重用旧数据,那么您肯定会发生内存泄漏.
我经常看到的一个来源是将方法附加到事件处理程序,但忘记在完成后取消注册它们,慢慢膨胀事件处理程序的大小和代码来执行.
第四,对.NET内存管理如何工作的错误理解可能意味着您要查看流程查看器中的内存使用情况,并注意到您的应用程序在内存使用方面不断增长.如果您有大量可用内存,GC可能无法经常运行,从而使您无法正确显示当前内存使用情况,而不是映射内存.
第五个,那个更难,到目前为止我只看到.NET中的一个资源管理错误,并且它已经预定在.NET 4.0中进行修复,它是将桌面屏幕复制到.NET映像中.
编辑:为了回应评论中的问题,如何避免保留超过必要的引用,那么唯一的方法就是这样做.
让我解释.
首先,如果你有一个长期运行的方法(例如,它可能正在处理磁盘上的文件,或下载某些东西,或类似的东西),并且你在方法的早期使用了对大数据结构的引用,那么运行部分,然后你没有将该数据结构用于该方法的其余部分,然后.NET,在发布版本中(而不是在调试器下运行)足够聪明,知道这个引用,尽管它保存在技术上在范围内的变量有资格进行垃圾回收.垃圾收集器在这方面非常积极.在调试构建中并在调试器下运行时,它将保留方法生命周期的引用,以防您在断点处停止时检查它.
但是,如果引用存储在声明方法的类中的字段引用中,那么它就不那么聪明,因为无法确定它是否会在以后重用,或者至少非常非常困难.如果不需要这个数据结构,你应该清除你所持有的引用,以便GC稍后再选择它.
简短的回答是非明显的参考.
要添加一些细节:
在收集AppDomain之前不会收集静态(可能等于进程关闭)
活动(记得取消订阅)
被阻止的终结器(终结器按顺序运行,因此任何阻塞终结器都将阻止收集所有其他可终结对象).示例包括无法访问STA线程的终结器.
死锁线程永远不会释放根源
忘记调用Monitor.Exit()(例如,当使用超时或跨方法时)可能会导致死锁,进而可能导致泄漏