我有一个管理对象调用COM服务器分配一些内存。 管理对象必须再次调用COM服务器管理的对象消失之前,以避免内存泄漏释放内存。 这个对象实现IDisposable
,以帮助确保正确的内存释放COM调用。
在事件的Dispose
方法不叫,我想对象的终结,以释放内存。 麻烦的是,最后确定的规则是,你不能访问任何引用,因为你不知道什么其他物体已经GC'd和/或你之前敲定做。 这使得仅可触摸对象的状态是字段(句柄是最常见的)。
但调用COM服务器包括通过一个运行时可调用包装(RCW),以便释放,我有一个cookie存储在一个领域内存去。 是RCW安全地从一个终结(是否保证在这一点上还没有GC'd或完成)打电话?
对于那些你不熟悉的终结,虽然终结线程,而其运行的托管应用程序域的后台运行,在这些接触引用的情况下,理论上是好的,也终结发生在应用程序域关机,并以任意顺序 -不只是引用关系的顺序。 这限制了你可以假设是安全的,从你的终结碰。 为管理对象的任何引用可能是“坏”(收集内存),即使引用非空。
更新 :我刚刚试了一下,得到了这一点:
类型的未处理的异常“System.Runtime.InteropServices.InvalidComObjectException”发生在MyAssembly.dll程序
不能使用已从与其基础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是不是托管本身正常的情况下,我被告知这应该工作。
不,它是不是安全地从终结器线程访问RCW。 当您达到了终结器线程,你有没有保证,RCW还活着。 这是可能的它是领先你对象在终结队列中,因此你的析构函数终结器线程上运行的时间释放。