当我们没有析构函数时,为什么要调用SuppressFinalize

我有几个问题,我无法得到正确的答案。

1)当我们没有析构函数时,为什么我们应该在Dispose函数中调用SuppressFinalize。

2)Dispose和finalize用于在对象被垃圾收集之前释放资源。 无论是托管资源还是非托管资源我们都需要释放它,那么为什么我们需要在dispose函数中使用一个条件,当我们从IDisposable调用这个重写函数时传递’true’:从finalize调用时Dispose并传递false。

请参阅我从网上复制的以下代码。

class Test : IDisposable { private bool isDisposed = false; ~Test() { Dispose(false); } protected void Dispose(bool disposing) { if (disposing) { // Code to dispose the managed resources of the class } // Code to dispose the un-managed resources of the class isDisposed = true; } public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } } 

如果我删除布尔保护的Dispose函数并实现如下所示。

  class Test : IDisposable { private bool isDisposed = false; ~Test() { Dispose(); } public void Dispose() { // Code to dispose the managed resources of the class // Code to dispose the un-managed resources of the class isDisposed = true; // Call this since we have a destructor . what if , if we don't have one GC.SuppressFinalize(this); } } 

我在这里走出困境,但……大多数人不需要完整的处置模式。 它可以直接访问非托管资源(通常通过IntPtr )并面向inheritance。 大多数情况下,这些都不是实际需要的。

如果您只是持有对实现IDisposable其他东西的引用,那么您几乎肯定不需要终结器 – 无论是什么保存资源都直接负责处理它。 你可以做这样的事情:

 public sealed class Foo : IDisposable { private bool disposed; private FileStream stream; // Other code public void Dispose() { if (disposed) { return; } stream.Dispose(); disposed = true; } } 

请注意,这不是线程安全的,但这可能不是问题。

通过不必担心子类直接保存资源的可能性,您不需要抑制终结器(因为没有终结器) – 并且您也不需要提供自定义处理的子类方法。 没有inheritance,生活就更简单了。

如果你确实需要允许不受控制的inheritance(即你不愿意打赌子类会有非常特殊的需求),那么你需要寻找完整的模式。

请注意,使用.NET 2.0中的SafeHandle ,您需要自己的终结器甚至比在.NET 1.1中更少。


为了解决为什么首先存在disposing标志的问题:如果你在终结器中运行,你引用的其他对象可能已经完成。 你应该让他们自己清理,你应该只清理你直接拥有的资源。

保留第一个版本,它更安全,是配置模式的正确实现。

  1. 调用SuppressFinalize告诉GC你已经完成了所有的破坏/处理(你的类所拥有的资源),并且它不需要调用析构函数。

  2. 如果使用您的类的代码已经调用dispose,您需要进行测试,并且不应该告诉GC再次处置。

请参阅此 MSDN文档(Dispose方法应调用SuppressFinalize)。

以下是主要事实

1)Object.Finalize是你的类在具有Finalizer时重写的内容。 ~TypeName()析构函数方法只是’覆盖Finalize()’等的简写

2)如果在最终化之前处理Dispose方法中的资源(即从使用块中出来等),则调用GC.SuppressFinalize。 如果您没有Finalizer,那么您不需要这样做。 如果你有一个Finalizer,这可以确保该对象从Finalization队列中取出(因此我们不会处理两次,因为Finalizer通常也会调用Dispose方法)

3)您将Finalizer实现为“故障安全”机制。 确保终结器运行(只要CLR没有中止),因此它们允许您确保在未调用Dispose方法的情况下清除代码(可能程序员忘记在’using’中创建实例块等

4)终结器是昂贵的,因为具有终结器的类型不能在Generation-0集合中进行垃圾收集(效率最高),并且在F-Reachable队列中引用它们被提升为Generation-1,因此它们代表了GC根。 直到GC执行Generation-1集合才能调用终结器,并释放资源 – 所以只有在非常重要时才实现终结器 – 并确保需要Finalization的对象尽可能小 – 因为所有对象都可以你的终结对象将被提升到第一代也。

1.回答第一个问题

基本上,如果您的类没有finalize方法(析构函数),则不必调用SuppressFinalize方法。 我相信即使由于缺乏知识而没有最终确定方法,人们也会打电话给SupressFinalize。

2.回答第二个问题

Finalize方法的目的是释放未管理的资源。 最重要的是要理解,当对象在终结队列中时,会调用Finalize方法。 垃圾收集器收集可以销毁的所有对象。 垃圾收集器在销毁之前将已完成的对象添加到终结队列。 还有另一个.net后台进程为最终化队列中的对象调用finalize方法。 到后台进程执行finalize方法时,该特定对象的其他托管引用可能已被破坏。 因为在完成执行时没有特定的顺序。 因此,Dispose Pattern希望确保finalize方法不会尝试访问托管对象。 这就是为什么托管对象进入finalize方法无法访问的“if(disposing)”子句的原因。

你应该总是调用SuppressFinalize(),因为你可能有(或将来有)一个实现Finalizer的派生类 – 在这种情况下你需要它。

假设您有一个没有Finalizer的基类 – 并且您决定不调用SuppressFinalize()。 然后3个月后,您添加一个添加Finalizer的派生类。 您可能会忘记前往基类并添加对SuppressFinalize()的调用。 如果没有终结器,则调用它是没有害处的。

我建议的IDisposable模式发布在这里: 如何正确实现Dispose模式