重现步骤:

这是我的代码:

    using (TestClass test = new TestClass())
    {

    }

    GC.Collect();
    GC.WaitForPendingFinalizers();
    GC.Collect();


这就是我定义TestClass的方式:

public class TestClass : IDisposable
{
    public void Dispose()
    {
        Dispose(true);
        //GC.SuppressFinalize(this);
    }

    protected virtual void Dispose(bool disposing)
    {
        if (disposing)
        {
            Console.WriteLine("Disposing TestClass.");
        }
    }

    ~TestClass()
    {
        Dispose(false);
        Console.WriteLine("TestClass Finalizer called");
    }
}


预期行为:
我确实看到在using语句之后按预期方式打印了“处置TestClass”,但是我也希望在运行我的GC命令之后打印“调用TestClass的终结器”。我确保不跳过调用GC.SuppressFinalize(this);在Dispose方法中。看起来,即使已超出范围的变量也无法最终确定。它们似乎在程序退出之前就已完成。

实际行为:
我只看到在using语句之后按预期方式打印了“ Dispose TestClass”,但在GC命令之后看不到“ TestClass Finalizer被调用”。我只在程序退出前看到它。

这不是内存泄漏吗?

如果将其转换为非一次性类并更新如下代码,则可以看到在GC命令之后调用了终结器。

TestClass test = new TestClass();
test = null;

GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();


public class TestClass
{
    ~TestClass()
    {
        Console.WriteLine("TestClass Finalizer called");
    }
}

最佳答案

根据微软对Object.Finalize Method ()的描述


  终结器执行的确切时间是不确定的。为确保确定性地释放类实例的资源,请实现Close方法或提供IDisposable.Dispose实现。


将终结器视为第二道防线。如果程序无法调用CloseDispose,则终结器将进行更改以更正省略。

这仍将确保,例如,文件将在程序退出时关闭,除非另一个终结器没有退出并因此阻塞了其他终结器,或者如果灾难性的异常残酷地终止了该程序。

这不是内存泄漏。如果内存不足,则垃圾回收器(GC)可以决定释放资源并在程序退出之前很长时间调用终结器。

关于c# - 终结器未调用一次性类型对象,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/42329589/

10-13 09:31