“内存泄漏”剖析
在.NET的角度来看:
我见过的最好的解释是免费编程电子书基础的第7章。
基本上,在.NET中 ,当被引用的对象被植入时会发生内存泄漏,因此无法进行垃圾收集。 当您坚持超出预期范围的引用时,会发生意外。
当你开始发生OutOfMemoryException异常或者你的内存使用超出你的预期( PerfMon有很好的内存计数器)时,你会知道你有泄漏。
了解.NET的内存模型是避免它的最佳方式。 具体来说,了解垃圾收集器如何工作以及参考如何工作 - 再次,我将您引用到电子书的第7章。 另外,请注意常见的陷阱,可能是最常见的事件。 如果对象A被注册到对象B上的事件,则对象A将继续存在,直到对象B消失,因为B持有对A的引用。 解决方案是在您完成后取消注册您的活动。
当然,一个好的内存配置文件可以让你看到你的对象图,并探索对象的嵌套/引用,以查看引用来自何处以及根对象是负责任的(红门蚂蚁配置文件,JetBrains dotMemory,memprofiler非常好选择,或者您可以使用纯文本WinDbg和SOS ,但我强烈建议您使用商业/视觉产品,除非您是真正的专家)。
我相信非托管代码受其典型内存泄漏的影响,但共享引用由垃圾收集器管理。 我最后一点可能是错的。
严格来说,内存泄漏消耗了程序“不再使用”的内存。
“不再使用”有多个含义,它可能意味着“不再提及它”,即完全不可恢复,或者可能意味着被引用,可恢复,未被使用,但程序仍然保留引用。 只有后者适用于.Net才能完美管理的对象 。 然而,并不是所有的类都是完美的,并且在某些时候,底层的非托管实现可能会永久性地泄露资源。
在所有情况下,应用程序消耗的内存都比严格需要的要多。 双方的影响,取决于泄露的数量,可能从无到有,过度收集造成的放缓,最终导致一系列内存异常,最后导致严重错误,随后强制进程终止。
当监视显示在每个垃圾收集周期后越来越多的内存分配给您的进程时,您知道应用程序存在内存问题。 在这种情况下,您要么记忆太多,要么底层的非托管实现泄漏。
对于大多数泄漏,资源在进程终止时被恢复,但是在某些精确情况下,某些资源并不总是被恢复,GDI游标句柄因此而臭名昭着。 当然,如果你有一个进程间通信机制,在另一个进程中分配的内存不会被释放,直到该进程释放或终止。
我认为“什么是内存泄漏”和“有什么影响”的问题已经得到了很好的回答,但是我想在其他问题上增加更多的内容......
如何理解你的应用程序是否泄漏
一种有趣的方法是在所有堆和#Gen 2集合中打开perfmon并为#字节添加跟踪,每种情况都只是看你的过程。 如果执行特定功能会导致总字节数增加,并且该内存在下一代Gen 2收集之后仍然分配,那么您可能会说该功能会泄漏内存。
如何预防
其他好的意见已经给出。 我只是补充说,也许.NET内存泄漏最常被忽视的原因是将事件处理程序添加到对象而不删除它们。 附加到对象的事件处理程序是对该对象的引用形式,因此即使在所有其他引用都去之后也会阻止收集。 始终记住要分离事件处理程序(在C#中使用-=
语法)。
当进程退出时泄漏消失了,COM互操作怎么办?
当你的进程退出时,所有映射到其地址空间的内存都被操作系统回收,包括从DLL提供的任何COM对象。 相对而言很少,COM对象可以通过单独的进程提供服务。 在这种情况下,当您的进程退出时,您可能仍然对在您使用的任何COM服务器进程中分配的内存负责。
链接地址: http://www.djcxy.com/p/66919.html