【问题标题】:How to use Finalize with managed resources?如何将 Finalize 与托管资源一起使用?
【发布时间】:2012-04-15 17:27:28
【问题描述】:

在类 B 的最后一个实例最终确定之前,如何将类 A 的实例定义为存在,我不是 100% 清楚。

或者换句话说,我希望所有 BB 最终确定内的 A 中调用 close&dispose 方法...这发生在 A 本身完成之前。

场景:

A.我有一个非托管资源的托管包装器。打个比方,我们把 A 称为文件系统

B.引用 A 的托管资源,这些资源又通过 A 包装器请求非托管资源。为了类比,我们称 B 为文件。

附加请求 --> 我希望 using 语法能够很好地发挥作用。即显式调用 using dispose 不应释放非托管资源。该对象将存在于对象池中。它应该只在它离开对象池时被释放。

class SomeClass() : IDisposable{

    public SomeClass(){}

    public ~SomeClass(){
       // dispose of unmanaged here?
    }

    // Dispose(bool disposing) executes in two distinct scenarios.
    // If disposing equals true, the method has been called directly
    // or indirectly by a user's code. Managed and unmanaged resources
    // can be disposed.
    // If disposing equals false, the method has been called by the
    // runtime from inside the finalizer and you should not reference
    // other objects. Only unmanaged resources can be disposed.
    public void Dispose(bool disposing) {
        if (disposing) {
            // dispose managed
        } else {
            // dispose unmanaged?
        }
    }

    public void Dispose() {
        Dispose(true);
        //GC.SuppressFinalize(this);
    }

}

参考资料:

[1]Why Finalize method not allowed to override

[2] CLR 通过 C Sharp 第三版。通道。 21. 关键终结器对象。特别是第 537 页“使用托管资源完成”

【问题讨论】:

  • 您正在尝试完成垃圾收集器所做的工作。只要存在对 B 对象的实时引用,就无法收集 A。一旦收集了所有 B,A 也将被收集。现在,它们最终确定的顺序不再重要了。
  • @HansPassant:这是否包括 IsFinalizingForUnload + HasShutdownStarted 场景?
  • 这些条件没有什么特别之处,只是程序关闭时的终结器扫描。我很不清楚你为什么要为此烦恼。
  • @HansPassant:这一切都是在发现 Dispose (通过使用)关闭了不应该关闭的代码之后开始的。这导致试图更好地处理 dispose + unmanaged ......并且......结果发现了一些边缘案例 + .net 框架约定。
  • @HansPassant:学习易碎+复活会给人信心。顺便说一句:在这种情况下,不最终实现子对象(如框架所做的那样)是最好的前进方式。顺便说一句:AddMemoryPressure、RemoveMemoryPressure 和 ReRegisterForFinalize 看起来对于某些罕见的情况非常有用。否则我不会知道他们。

标签: c# clr finalizer clr4.0


【解决方案1】:

您通常无法控制最终确定顺序。不过,您可以使用CriticalFinalizerObject 控制两阶段顺序。另请查看 SafeHandle 基础架构以及 FileStream 是如何实现的。

如果这还不够,您可以通过从静态类成员(例如列表或字典)创建对象引用来任意控制生命周期。只有当您释放这些引用时,才会发生最终确定。因此,您将创建一个对 A 的引用,一旦您注意到对 B 的 GCHandle 已变得无效,您就会清除该引用。

【讨论】:

  • in [2] Richter 先生在 pp. 537 上说:“虽然终结几乎专门用于释放本机资源,但它有时也可用于托管资源。”听起来好像有办法。不过,我还没有 100% 理解这一章……因此我向专家们求助。
  • 我猜他指的是对对象池使用终结的可能性。但是,除了我提到的之外,您无法控制顺序。
猜你喜欢
  • 1970-01-01
  • 2019-08-29
  • 1970-01-01
  • 2023-03-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-04-06
相关资源
最近更新 更多