簡體   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