简体   繁体   English

在终结器中处理IDisposables列表

[英]dispose a list of IDisposables in the finalizer

I have a couple of unmanaged memory structures used to communicate with c++ dlls. 我有几个非托管内存结构用于与c ++ dll通信。 Each such structure has to be freed manually, so I wrap it in a MyUnmanagedStructure which implements IDisposable . 每个这样的结构都必须手动释放,所以我将它包装在一个实现IDisposableMyUnmanagedStructure中。

I always need a variable number of these structures together, so I have a collection MyUnmanagedStructureCollection which also implements IDisposable. 我总是需要一些可变数量的这些结构,所以我有一个MyUnmanagedStructureCollection集合,它也实现了IDisposable。

(see below for the minimal example code) (参见下面的最小示例代码)

As long as the user of my library always calls Dispose() or wraps the collection with using() {} there is no problem, but I cannot assure that. 只要我的库的用户总是调用Dispose()或using() {}包装集合就没有问题,但我无法保证。 I do not want to leak memory even if the user does not dispose the collection manually. 即使用户没有手动处理集合,我也不想泄漏内存。

When the MyUnmanagedStructureCollection.Dispose() method is called by the garbage collection via finalizer instead, then as far as I understand I cannot be sure that my private List<MyUnmanagedStructure> has not been garbage collected already, so how can I dispose of each structure in that case? 相反,当垃圾收集通过终结器调用MyUnmanagedStructureCollection.Dispose()方法时,据我所知,我不能确定我的private List<MyUnmanagedStructure>还没有被垃圾收集,所以如何处理每个结构在这种情况下?

In my finalizing code, should I attempt to iterate over the list, hoping that it has not been garbage collected yet? 在我的最终化代码中,我是否应该尝试遍历列表,希望它还没有被垃圾回收?

Is it good practise to do this in a try/catch block, catching ObjectDisposedException? 在try / catch块中执行此操作,捕获ObjectDisposedException是一种好习惯吗?

Or should I let each unmanagedStructure "fend for itself", relying on the individual finalizers, and simply do nothing in the finalizer of my collection? 或者我应该让每个unmanagedStructure“自生自灭”,依靠个人终结者,而在我的收藏品的终结者中什么也不做?

public class MyUnmanagedStructureCollection : IDisposable
{
    private List<MyUnmanagedStructure> structures;
    private bool disposed = false;

    #region standard IDIsposable pattern
    public ~MyUnmanagedStructureCollection()
    {
        this.Dispose(false);
    }

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

    protected virtual void Dispose(bool disposing)
    {
        if (!disposed)
        {
            // Dispose unmanaged resources 
            // Should not access managed resources, 
            // the garbage collection may have claimed them already!

            // PROBLEM!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
            // this.structures is a List<MyUnmanagedStructure>; so is a managed resource!!!

            foreach (var structure in this.structures)
                 structure.Dispose(disposing)
            this.removeAllMemoryPressure();

            if (disposing) 
            {
                // Dispose managed resources.
                this.structures.Clear();
                this.structures = null;
            }

        }
        disposed = true;
    }
}


public class MyUnmanagedBuffer : IDisposable
{
...
}

The way the GC works is: GC的工作方式是:

  1. Find all reachable objects 查找所有可到达的对象
  2. Enqueue all unreachable objects with a finalizer into the finalization queue 使用终结器将所有无法访问的对象排入结束队列
  3. Mark all objects that are reachable from from the finalization queue as reachable 将从终结队列中可到达的所有对象标记为可到达
  4. Free the remaining unreachable objects 释放剩余的无法访问的对象

An object that's referenced from an object whose finalizer is running cannot have been garbage collected yet. 从终结器正在运行的对象引用的对象尚未被垃圾回收。

The only thing you need to be careful about is that the order of finalization is undefined. 您唯一需要注意的是,最终确定的顺序是未定义的。 So the elements of the list might have been finalized yet, but not collected. 因此,列表的元素可能尚未最终确定,但未收集。 Finalization is guaranteed to be single threaded, so you need locking too. 最终确保是单线程的,所以你也需要锁定。

One generally tries to avoid such finalization chains, since independent finalization is simpler. 人们通常会试图避免这种终结链,因为独立定型更简单。 But if some objects need to be disposed before others, such a construction is unavoidable. 但是,如果某些物体需要在其他物体之前处置,那么这种结构是不可避免的。

You should also consider critical finalization using SafeHandle s. 您还应该考虑使用SafeHandle关键定型。


Reachability 可达性

One of the guidelines for finalization is that a Finalize method shouldn't touch other objects. 最终确定的指导原则之一是Finalize方法不应该触及其他对象。 People sometimes incorrectly assume that this is because those other objects have already been collected. 人们有时会错误地认为这是因为已经收集了其他对象。 Yet, as I have explained, the entire reachable graph from a finalizable object is promoted. 然而,正如我已经解释过的那样,促进了可终结对象的整个可到达图形。

The real reason for the guideline is to avoid touching objects that may have already been finalized. 指南的真正原因是避免接触可能已经完成的对象。 That's because finalization is unordered. 那是因为终结是无序的。

Chris Brumme on finalization Chris Brumme最终定稿

Since you're MyUnmanagedBuffer class is a managed resource from point-of-view of your MyUnmanagedStructureCollection class, I think it should handle it as such. 既然你MyUnmanagedBuffer类是从你的角度点的受管资源MyUnmanagedStructureCollection类,我觉得应该把它处理这样的。 This would mean that the MyUnmanagedStructureCollection.Dispose(bool) method would be as below. 这意味着MyUnmanagedStructureCollection.Dispose(bool)方法如下所示。

protected virtual void Dispose(bool disposing) {
    if (!disposed) {
        // Dispose unmanaged resources 
        // Should not access managed resources, 
        // the garbage collection may have claimed them already!

        if (disposing) {
            // Dispose managed resources.
            // This means that we try to dispose all items in the structures collection.
            if (this.structures != null) {
                foreach (var structure in this.structures) {
                    structure.Dispose(disposing);
                    this.removeAllMemoryPressure(); // What does this?
                }
                this.structures.Clear();
                this.structures = null;
            }
        }
    }

    disposed = true;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM