繁体   English   中英

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

[英]Does a COM object get released by the CLR when the thread that created it terminates?

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

是的,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()往往被不必要地使用。

这是我设法重现Hans Passant答案中的行为的示例代码。 我可以单击按钮1来创建一个对象,然后当我在创建线程终止后单击按钮2来访问它时,我得到错误“已经与其底层RCW分离的COM对象无法使用”。

Public Class Form1

   Dim comRef As Microsoft.Office.Interop.Outlook.Application

   Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
      Dim t As New System.Threading.Thread(AddressOf CreateApplication)
      t.SetApartmentState(Threading.ApartmentState.STA)
      t.Start()
   End Sub

   Private Sub CreateApplication()
      comRef = New Microsoft.Office.Interop.Outlook.Application
   End Sub 

   Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
      TextBox1.Text = comRef.DefaultProfileName
   End Sub
End Class

暂无
暂无

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

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