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

如果没有调用Dispose方法,我希望对象的终结器释放内存。问题在于,终结处理的规则是您不得访问任何引用,因为您不知道在您进行GC和/或终结处理之前还有哪些其他对象。这使唯一可触摸的对象状态为字段(句柄是最常见的)。

但是,调用COM服务器涉及通过运行时可调用包装(RCW),以释放内存,而我将cookie存储在字段中。从终结器调用该RCW是否安全(是否保证此时尚未进行GC或终结)?

对于那些不熟悉终结处理的人,尽管终结器线程在运行时在托管应用程序域的后台运行,在这种情况下,从理论上讲,可以通过引用进行操作,终结处理也可以在应用程序域关闭时发生,并且以任何顺序进行-只是按引用关系顺序。这限制了您可以认为可以从终结器安全触摸的内容。即使对托管对象的任何引用都是非null的,它也可能是“坏的”(收集的内存)。

更新:我只是试过了,得到了这个:


myassembly.dll中发生了类型为'System.Runtime.InteropServices.InvalidComObjectException'的未处理异常

附加信息:不能使用已与其基础RCW分离的COM对象。

最佳答案

我从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不托管自己,我被告知这应该可行。

关于.net - 从终结器调用RCW是否安全?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/1573977/

10-13 01:14