忽略IDisposable会导致内存泄漏吗?

在我写的答案的评论中,我们讨论了内存泄漏和IDisposable ,我们没有得出任何真正的结论。

处理非托管资源的类可能实现IDisposable 。 如果忽略它并且既没有调用Dispose也没有在using包装对象 – 会导致非托管资源被泄露吗? 或者,当GC收集物体时,它会被正确清理吗?

我们可以假设处理非托管资源的类具有IDisposable的正确实现,包括终结器等。

它不会导致内存泄漏 。 事实上,Dispose与内存管理完全无关。

它会造成资源泄漏 。 虽然GC通常会清理它,但这可能太罕见而且太迟了。

省略处理( using )可能会减慢甚至崩溃您的应用程序。 在文件资源或Db连接的情况下,它甚至可能导致其他应用程序出现问题。

我不会导致托管内存泄漏。 它可能导致引用的非托管代码泄漏。 但它更糟糕的是:现代系统上的内存足够丰富,你可以经常使用一段时间的漏洞。 见证Mozilla Firefox:曾经(它仍然?)像筛子一样泄漏,数百万人乐于使用它。

更大的问题是其他资源可能与内存无关。 示例包括数据库连接,系统I / O句柄,套接字句柄,文件句柄等。 如果您不小心正确使用IDisposable,这些都是您可以在自己的系统上轻松创建拒绝服务情况的所有项目。

只是为Henk和Joel的答案添加一点

您所描述的内容经常在DB Connections上发生。 已经添加了ADO.NET性能计数器 NumberOfReclaimedConnections 。 这个柜台追踪……

通过垃圾收集回收的连接数,其中应用程序未调用Close或Dispose 。 不明确关闭或处理连接会损害性能。

性能命中通常需要更长时间,等待连接被释放。 这也可能导致连接超时,而不是内存问题。

如果IDisposable对象具有取消分配非托管内存的终结器,则在调用终结器时(在GC标记为收集并放置在终结器队列中之后)内存将是空闲的,但是如果没有任何终结器并且从不调用Dispose() ,然后可以泄漏内存并仅在进程终止时重新声明。

未能在订阅来自较长寿命对象的事件的对象上调用IDisposable将扩展订阅者的内存分配生命周期,以扩展到发布者的内存分配生命周期。 如果在发布者的生命周期内可能附加和放弃的订阅者数量没有上限,则这将构成无限制的内存泄漏。

最重要的问题是GC 何时运行。

参加以下课程

 class GcTest { private Stopwatch sw = new Stopwatch(); public GcTest() { sw.Start(); } ~GcTest() { sw.Stop(); Console.WriteLine("GcTest finalized in " + sw.ElapsedMilliseconds + " ms"); } } 

如果您愿意,可以在Console.WriteLine上设置断点。

创建一个空的Windows窗体应用程序,并在表单加载事件中只是实例化一个新的GcTest

 private void Form1_Load(object sender, EventArgs e) { var gcTest = new GcTest(); } 

运行您的应用程序并等待终结器运行。
很可能在您关闭应用程序之前它不会运行。

据我所知,GC不会调用Dispose。 你必须自己明确地调用它或使用。 所以答案是:是的,如果类处理在Dispose中释放的非托管资源,如果不调用Dispose,则类将泄漏。