忽略idisable是否会导致内存泄漏

本文关键字:内存 泄漏 idisable 是否 忽略 | 更新日期: 2023-09-27 18:04:06

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

处理非托管资源的类可能实现IDisposable。如果忽略这一点,既不调用Dispose也不将对象包装在using中-这会导致未管理的资源被泄露吗?或者当GC收集对象时,它会被正确地清理吗?

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

忽略idisable是否会导致内存泄漏

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

将创建一个资源泄漏。虽然GC通常会清理它,但这可能太少见,也太迟了。

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

我不会导致托管的内存泄漏。它可以在引用的非托管代码中导致泄漏。但更糟糕的是:现代系统上的内存足够充足,即使出现严重的泄漏,也可以维持一段时间。以Mozilla Firefox为例:它曾经(现在还会吗?)像筛子一样泄露信息,但数百万人都乐于使用它。

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

为Henk和Joel的回答添加一点内容

你所描述的情况在DB连接中经常发生。够了,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窗体应用程序,并在form load事件中实例化一个新的GcTest

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

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

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