当创建它的线程终止时,CLR是否释放了COM对象?

Blu*_*kMN 4 .net c# vb.net com com-interop

我一直无法弄清楚如何搜索这种怀疑的确认,但我看到证据表明在一个线程上创建的COM对象不再可用于其他线程(已经与其底层RCW分离的COM对象无法使用)一旦代码在创建它的线程上停止执行(并且该线程可能已终止).这是一个非常隐蔽的问题,因为我在System.Runtime.InteropServices.Marshal.ReleaseComObject整个代码中都有调用,但我无法识别是否有任何调用导致此错误.最后我得出结论,当辅助线程停止执行时,COM对象显然被隐式释放.这可能是真的吗?这是记录在案的行为?

Han*_*ant 6

是的,COM对象往往具有强大的线程亲和力.线程不是COM中的次要实现细节.与.NET不同,COM为COM类提供了线程安全保证.COM可以发布它支持的线程类型,"公寓"(即"非线程安全")是一个非常常见的选择.COM确保满足这些要求,而无需程序必须提供任何帮助.从一个线程到另一个线程的调用,以便始终以线程安全的方式使用该对象是自动的.在.NET代码中,您通常必须自己使用Control.BeginInvoke或Dispatcher.BeginInvoke这样做.

这样做的一个自动结果是拥有一个或多个允许退出的COM对象的线程将自动释放这些对象.这是必要的,因为不再有办法满足线程安全要求.在这之后试图使用它们会炸弹.除了确保线程保持足够长的时间以保持对这些对象的维护之外,没有办法解决这个问题.类似地,您需要保持UI线程的活动时间足够长,以确保Dispatcher.BeginInvoke仍然可以在.NET中工作.

Fwiw,是的,使用Marshal.ReleaseComObject()可以给你很多关于这一点.显式内存管理具有生成错误程序的悠久历史,并且自动垃圾收集提供了治愈.GC非常有能力在没有你帮助的情况下发布COM对象,并且永远不会出错.它只需要更长的时间来解决它.如果您知道COM对象具有异常高的资源使用率,并且需要确定性地释放它,那么您执行与为昂贵的.NET对象图执行完全相同的操作:GC.Collect()有助于此.检查这个答案是因为Marshal.ReleaseComObject()往往被不必要地使用.