【问题标题】:In c#,can we use finalize to dispose the managed source?在c#中,我们可以使用finalize来处理托管源吗?
【发布时间】:2013-07-09 07:22:33
【问题描述】:

根据 IDisposable 的使用方式,微软建议使用 finalize 来释放非托管源。 http://msdn.microsoft.com/en-us/library/system.idisposable%28v=VS.80%29.aspx

但是如果我们在 finalize 中编写一些代码来发布托管源代码会发生什么? 也就是说当 GC 调用 finalize 释放一些托管源时,会发生什么?

【问题讨论】:

标签: c# garbage-collection dispose finalize


【解决方案1】:

一般来说,使用Finalize 清理外部托管资源是没有用的,而且可能很危险。当对象终结器运行时,它持有的托管资源可能是:

  1. 由于运行了它们的终结器而已经清理,在这种情况下处置它们将毫无用处。
  2. 尚未清理,但被识别为未被任何活动对象引用,在这种情况下,无论当前执行的终结器是否尝试清理它们,它们的终结器都会在适当的时候运行。
  3. 其他活动对象仍在使用,在这种情况下,当前运行的终结器不应清理它们。

在某些情况下,让终结器在其他托管对象上调用清理代码可能会有所帮助,但这种调用通常只适用于对象知道彼此内部细节的情况,并且通常应该使用 @ 来执行987654322@ 或 internal 方法,或使用私人交换的委托。在某些情况下,例如,可能有两个或多个对象相互了解,并且具有必须以特定顺序运行的终结器。

例如,可能有一个类的目的是向 USB 设备发送数据,而另一个类的目的是控制连接到该设备的设备。如果后一个类想要确保设备接收到“关闭”命令,则可能需要其终结器在 USB 连接类终结器关闭连接之前发送命令。处理此问题的最简洁方法可能是让 USB 连接对象的构造函数接受将从其终结器调用的回调。如果这个类没有这样的特性,事情可能会很糟糕。另一种方法可能是让一个对象与包装器分开,该对象包含清理所需的所有信息,以及包装器对象的WeakReference,并具有一个计时器滴答事件,如果WeakReference 死了,它将执行清理。如果计时器绑定到创建包装器对象的线程,那么即使包装器对象被放弃,也可能允许执行清理,前提是线程仍然处于活动状态(如果可能不存在,事情会变得更加复杂)。

【讨论】:

    【解决方案2】:

    无需为托管代码编写 Dispose/Finalize。 bcz 当不再引用该对象时,它将被 CLR 删除。 Dispose 方法是为文件处理程序或数据库命令等非托管代码编写的。

    【讨论】:

    • 完全错误。 IDisposable 的唯一目的是确定性资源清理,无论这些资源的性质如何(事件可能是托管资源,取消订阅事件是释放托管资源的一种方式)。另一方面,Finalize 是清理 非托管 资源的最后机会。不应该依赖Finalize 来关闭文件句柄。文件句柄必须在此时此地关闭,当它变得不必要时。但如果出现异常,最好关闭文件句柄一段时间,而不是根本不关闭它。
    【解决方案3】:

    为什么(或者更好的是,如何)发布在终结器中管理的东西?当前对象拥有的所有东西此时都已被视为垃圾,并将在垃圾收集器的下一次运行中被收集。并且当前拥有的所有内容都无法发布,因为其他内容可能仍会引用它。

    【讨论】:

      【解决方案4】:

      这是一个不好的做法一般来说。在终结器代码中,您不能依赖对象及其托管资源的状态 - 它们已经可以被收集或处置/终结。此外,您不能依赖 CLR 调用 Finalize 的顺序。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-07-30
        • 2020-01-16
        • 2019-01-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-09-03
        相关资源
        最近更新 更多