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

发布于 2024-08-28 17:58:40 字数 1279 浏览 6 评论 0原文

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

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

2) Dispose 和 Finalize 用于在对象被垃圾收集之前释放资源。无论它是托管资源还是非托管资源,我们都需要释放它,那么为什么我们需要在 dispose 函数中添加一个条件,即当我们从 IDisposable:Dispose 调用此重写函数时传递“true”,而从 Finalize 调用时传递 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);
     }
   }       

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 .

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.

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.

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

剩余の解释 2024-09-04 17:58:40

我在这里冒险,但是......大多数人不需要需要成熟的处置模式。它被设计为在直接访问非托管资源(通常通过 IntPtr)和继承方面是可靠的。大多数时候,这些实际上都不是必需的。

如果您只是持有对实现 IDisposable 的其他内容的引用,那么您几乎肯定不需要终结器 - 直接持有资源的任何内容都负责处理该资源。您可以这样做:

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

    // Other code

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

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

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

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

请注意,与 .NET 1.1 中相比,使用 .NET 2.0 中的 SafeHandle 时,您需要自己的终结器的情况甚至更加罕见。


首先要解决您关于为什么有一个 dispose 标志的观点:如果您在终结器中运行,则您引用的其他对象可能已经被终结。您应该让它们自行清理,并且您应该只清理您直接拥有的资源。

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.

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:

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.


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.

我乃一代侩神 2024-09-04 17:58:40

以下是主要事实

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

2) 如果您在最终确定之前(即从 using 块等出来时)在 Dispose 方法中处置资源,则可以调用 GC.SuppressFinalize。如果您没有 Finalizer,则无需执行此操作。如果您有 Finalizer,这可以确保将对象从 Finalization 队列中取出(因此我们不会两次处理内容,因为 Finalizer 通常也会调用 Dispose 方法)

3)您将 Finalizer 实现为“故障安全”机制。终结器保证运行(只要 CLR 没有中止),因此它们允许您确保在未调用 Dispose 方法的情况下清理代码(也许程序员忘记在“使用”中创建实例) 4) 终结器非常昂贵,

因为具有终结器的类型无法在 Generation-0 集合(最有效)中进行垃圾收集,并且通过 F-Reachable 队列上对它们的引用提升到 Generation-1,因此它们代表 GC 根。直到 GC 执行第一代收集时,终结器才会被调用,并且资源才会被释放 - 因此仅在非常重要的情况下才实现终结器 - 并确保需要终结的对象尽可能小 - 因为所有可以你的可终结对象所达到的目标也将被提升到第一代。

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

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)

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.

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.

ˇ宁静的妩媚 2024-09-04 17:58:40

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

  1. 调用 SuppressFinalize 告诉 GC 您已经自行完成了所有销毁/处置(您的类持有的资源),并且不需要调用析构函数。

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

请参阅 MSDN 文档(Dispose 方法应调用抑制最终确定)。

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.

  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.

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

黯然#的苍凉 2024-09-04 17:58:40

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

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

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

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.

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.

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

白况 2024-09-04 17:58:40

1.回答第一个问题

基本上,如果您的类没有 Finalize 方法(析构函数),则不必调用 SuppressFinalize 方法。我相信由于缺乏知识,即使没有 Finalize 方法,人们也会调用 SupressFinalize。

2.第二个问题的回答

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

1. Answer for the first question

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.

2. Answer for the second question

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文