它是安全调用从一个终结的RCW?(Is it safe to call an RCW from a

2019-08-18 12:33发布

我有一个管理对象调用COM服务器分配一些内存。 管理对象必须再次调用COM服务器管理的对象消失之前,以避免内存泄漏释放内存。 这个对象实现IDisposable ,以帮助确保正确的内存释放COM调用。

在事件的Dispose方法叫,我想对象的终结,以释放内存。 麻烦的是,最后确定的规则是,你不能访问任何引用,因为你不知道什么其他物体已经GC'd和/或你之前敲定做。 这使得仅可触摸对象的状态是字段(句柄是最常见的)。

但调用COM服务器包括通过一个运行时可调用包装(RCW),以便释放,我有一个cookie存储在一个领域内存去。 是RCW安全地从一个终结(是否保证在这一点上还没有GC'd或完成)打电话?

对于那些你不熟悉的终结,虽然终结线程,而其运行的托管应用程序域的后台运行,在这些接触引用的情况下,理论上是好的,也终结发生在应用程序域关机,并以任意顺序 -不只是引用关系的顺序。 这限制了你可以假设是安全的,从你的终结碰。 为管理对象的任何引用可能是“坏”(收集内存),即使引用非空。

更新 :我刚刚试了一下,得到了这一点:

类型的未处理的异常“System.Runtime.InteropServices.InvalidComObjectException”发生在MyAssembly.dll程序

不能使用已从与其基础RCW分开COM对象:其他信息。

Answer 1:

我从CLR团队发现自己确实是不可靠的- 除非你对RCW分配的GCHandle,同时它还是安全的时候(当您第一次获得RCW)。 这确保了GC和终结,需要调用它最终确定的管理对象之前未总额的RCW。

class MyManagedObject : IDisposable
{
    private ISomeObject comServer;
    private GCHandle rcwHandle;
    private IServiceProvider serviceProvider;
    private uint cookie;

    public MyManagedObject(IServiceProvider serviceProvider)
    {
        this.serviceProvider = serviceProvider;
        this.comServer = this. serviceProvider.GetService(/*some service*/) as ISomeObject;
        this.rcwHandle = GCHandle.Alloc(this.comServer, GCHandleType.Normal);
        this.cookie = comServer.GetCookie();
    }

    ~MyManagedObject()
    {
        this.Dispose(false);
    }

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

    protected virtual void Dispose(bool disposing)
    {
        if (disposing)
        {
            // dispose owned managed objects here.
        }

        if (this.rcwHandle.IsAllocated)
        {
            // calling this RCW is safe because we have a GC handle to it.
            this.comServer.ReleaseCookie(this.cookie);

            // Now release the GC handle on the RCW so it can be freed as well
            this.rcwHandle.Free();
        }
    }
}

原来,在我的具体情况,我的应用程序托管CLR本身。 因此,它调用mscoree!CoEEShutdownCOM之前,终结线程得到运行,杀死了RCW,并导致InvalidComObjectException错误我所看到的。

但在CLR是不是托管本身正常的情况下,我被告知这应该工作。



Answer 2:

不,它是不是安全地从终结器线程访问RCW。 当您达到了终结器线程,你有没有保证,RCW还活着。 这是可能的它是领先你对象在终结队列中,因此你的析构函数终结器线程上运行的时间释放。



文章来源: Is it safe to call an RCW from a finalizer?