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

时间:2022-09-11 18:43:14

I have few Question for which I am not able to get a proper answer .

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

1) Why should we call SuppressFinalize in the Dispose function when we don't have a destructor .

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

2) Dispose and finalize are used for freeing resources before the object is garbage collected. Whether it is managed or unmanaged resource we need to free it , then why we need a condition inside the dispose function , saying pass 'true' when we call this overridden function from IDisposable:Dispose and pass false when called from a finalize.

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

See the below code I copied from net.

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

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);
     }
   }

what if I remove the boolean protected Dispose function and implement the as below.

如果我删除布尔保护的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);
     }
   }       

5 个解决方案

#1


19  

I'm going out on a limb here, but... most people don't need the full-blown dispose pattern. It's designed to be solid in the face of having direct access to unmanaged resources (usually via IntPtr) and in the face of inheritance. Most of the time, neither of these is actually required.

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

If you're just holding a reference to something else which implements IDisposable, you almost certainly don't need a finalizer - whatever holds the resource directly is responsible for dealing with that. You can make do with something like this:

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

public sealed class Foo : IDisposable
{
    private bool disposed;
    private FileStream stream;

    // Other code

    public void Dispose()
    {
        if (disposed)
        {
            return;
        }
        stream.Dispose();
        disposed = true;
    }
}

Note that this isn't thread-safe, but that probably won't be a problem.

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

By not having to worry about the possibility of subclasses holding resources directly, you don't need to suppress the finalizer (because there isn't one) - and you don't need to provide a way of subclasses customising the disposal either. Life is simpler without inheritance.

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

If you do need to allow uncontrolled inheritance (i.e. you're not willing to bet that subclasses will have very particular needs) then you need to go for the full pattern.

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

Note that with SafeHandle from .NET 2.0, it's even rarer that you need your own finalizer than it was in .NET 1.1.

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


To address your point about why there's a disposing flag in the first place: if you're running within a finalizer, other objects you refer to may already have been finalized. You should let them clean up themselves, and you should only clean up the resources you directly own.

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

#2


5  

Keep the first version, it is safer and is the correct implementation of the dispose pattern.

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

  1. Calling SuppressFinalize tells the GC that you have done all the destruction/disposing yourself (of resources held by your class) and that it does not need to call the destructor.

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

  2. You need the test in case the code using your class has already called dispose and you shouldn't tell the GC to dispose again.

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

See this MSDN document (Dispose methods should call SuppressFinalize).

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

#3


3  

Here are the main facts

以下是主要事实

1) Object.Finalize is what your class overrides when it has a Finalizer. the ~TypeName() destructor method is just shorthand for 'override Finalize()' etc

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

2) You call GC.SuppressFinalize if you are disposing of resources in your Dispose method before finalization (i.e. when coming out of a using block etc). If you do not have a Finalizer, then you do not need to do this. If you have a Finalizer, this ensures that the object is taken off of the Finalization queue (so we dont dispose of stuff twice as the Finalizer usually calls the Dispose method as well)

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

3) You implement a Finalizer as a 'fail safe' mechanism. Finalizers are guaranteed to run (as long as the CLR isnt aborted), so they allow you to make sure code gets cleaned up in the event that the Dispose method was not called (maybe the programmer forgot to create the instance within a 'using' block etc.

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

4) Finalizers are expensive as Types that have finalizers cant be garbage collected in a Generation-0 collection (the most efficient), and are promoted to Generation-1 with a reference to them on the F-Reachable queue, so that they represent a GC root. it's not until the GC performs a Generation-1 collection that the finalizer gets called, and the resources are released - so implement finalizers only when very important - and make sure that objects that require Finalization are as small as possible - because all objects that can be reached by your finalizable object will be promoted to Generation-1 also.

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

#4


2  

1. Answer for the first question

1.回答第一个问题

Basically, you don't have to call SuppressFinalize method if your class doesn't have a finalize method (Destructor). I believe people call SupressFinalize even when there is no finalize method because of lack of knowledge.

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

2. Answer for the second question

2.回答第二个问题

Purpose of the Finalize method is to free un-managed resources. The most important thing to understand is that, Finalize method is called when the object is in the finalization queue. Garbage collector collects all the objects that can be destroy. Garbage Collector adds objects those have got finalization to the finalization queue before destroy. There is another .net background process to call the finalize method for the objects those are in the finalization queue. By the time that background process execute the finalize method, that particular object's other managed reference may have been destroyed. Because there is no specific order when it comes to the finalization execution. So, the Dispose Pattern wants to make sure that finalize method do not try to access managed objects. That's why managed objects are going in side "if (disposing)" clause which is unreachable for the finalize method.

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

#5


1  

You should always call SuppressFinalize() because you might have (or have in the future) a derived class that implements a Finalizer - in which case you need it.

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

Let's say you have a base class that doesn't have a Finalizer - and you decided not to call SuppressFinalize(). Then 3 months later you add a derived class that adds a Finalizer. It is likely that you will forget to go up to the base class and add a call to SuppressFinalize(). There is no harm in calling it if there is no finalizer.

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

My suggested IDisposable pattern is posted here: How to properly implement the Dispose Pattern

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

#1


19  

I'm going out on a limb here, but... most people don't need the full-blown dispose pattern. It's designed to be solid in the face of having direct access to unmanaged resources (usually via IntPtr) and in the face of inheritance. Most of the time, neither of these is actually required.

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

If you're just holding a reference to something else which implements IDisposable, you almost certainly don't need a finalizer - whatever holds the resource directly is responsible for dealing with that. You can make do with something like this:

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

public sealed class Foo : IDisposable
{
    private bool disposed;
    private FileStream stream;

    // Other code

    public void Dispose()
    {
        if (disposed)
        {
            return;
        }
        stream.Dispose();
        disposed = true;
    }
}

Note that this isn't thread-safe, but that probably won't be a problem.

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

By not having to worry about the possibility of subclasses holding resources directly, you don't need to suppress the finalizer (because there isn't one) - and you don't need to provide a way of subclasses customising the disposal either. Life is simpler without inheritance.

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

If you do need to allow uncontrolled inheritance (i.e. you're not willing to bet that subclasses will have very particular needs) then you need to go for the full pattern.

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

Note that with SafeHandle from .NET 2.0, it's even rarer that you need your own finalizer than it was in .NET 1.1.

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


To address your point about why there's a disposing flag in the first place: if you're running within a finalizer, other objects you refer to may already have been finalized. You should let them clean up themselves, and you should only clean up the resources you directly own.

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

#2


5  

Keep the first version, it is safer and is the correct implementation of the dispose pattern.

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

  1. Calling SuppressFinalize tells the GC that you have done all the destruction/disposing yourself (of resources held by your class) and that it does not need to call the destructor.

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

  2. You need the test in case the code using your class has already called dispose and you shouldn't tell the GC to dispose again.

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

See this MSDN document (Dispose methods should call SuppressFinalize).

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

#3


3  

Here are the main facts

以下是主要事实

1) Object.Finalize is what your class overrides when it has a Finalizer. the ~TypeName() destructor method is just shorthand for 'override Finalize()' etc

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

2) You call GC.SuppressFinalize if you are disposing of resources in your Dispose method before finalization (i.e. when coming out of a using block etc). If you do not have a Finalizer, then you do not need to do this. If you have a Finalizer, this ensures that the object is taken off of the Finalization queue (so we dont dispose of stuff twice as the Finalizer usually calls the Dispose method as well)

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

3) You implement a Finalizer as a 'fail safe' mechanism. Finalizers are guaranteed to run (as long as the CLR isnt aborted), so they allow you to make sure code gets cleaned up in the event that the Dispose method was not called (maybe the programmer forgot to create the instance within a 'using' block etc.

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

4) Finalizers are expensive as Types that have finalizers cant be garbage collected in a Generation-0 collection (the most efficient), and are promoted to Generation-1 with a reference to them on the F-Reachable queue, so that they represent a GC root. it's not until the GC performs a Generation-1 collection that the finalizer gets called, and the resources are released - so implement finalizers only when very important - and make sure that objects that require Finalization are as small as possible - because all objects that can be reached by your finalizable object will be promoted to Generation-1 also.

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

#4


2  

1. Answer for the first question

1.回答第一个问题

Basically, you don't have to call SuppressFinalize method if your class doesn't have a finalize method (Destructor). I believe people call SupressFinalize even when there is no finalize method because of lack of knowledge.

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

2. Answer for the second question

2.回答第二个问题

Purpose of the Finalize method is to free un-managed resources. The most important thing to understand is that, Finalize method is called when the object is in the finalization queue. Garbage collector collects all the objects that can be destroy. Garbage Collector adds objects those have got finalization to the finalization queue before destroy. There is another .net background process to call the finalize method for the objects those are in the finalization queue. By the time that background process execute the finalize method, that particular object's other managed reference may have been destroyed. Because there is no specific order when it comes to the finalization execution. So, the Dispose Pattern wants to make sure that finalize method do not try to access managed objects. That's why managed objects are going in side "if (disposing)" clause which is unreachable for the finalize method.

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

#5


1  

You should always call SuppressFinalize() because you might have (or have in the future) a derived class that implements a Finalizer - in which case you need it.

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

Let's say you have a base class that doesn't have a Finalizer - and you decided not to call SuppressFinalize(). Then 3 months later you add a derived class that adds a Finalizer. It is likely that you will forget to go up to the base class and add a call to SuppressFinalize(). There is no harm in calling it if there is no finalizer.

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

My suggested IDisposable pattern is posted here: How to properly implement the Dispose Pattern

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