2009-08-12 59 views
6

我有出現內存泄漏一個WindowsForms應用程序,所以我用展鵬的螞蟻內存分析器來看看我懷疑的對象,發現他們是由物體在終結隊列只開了。太好了,到底什麼是Finalizer Queue?你能指出我的最佳定義嗎?你能分享任何軼事建議嗎?什麼是Finalizer隊列和Control + ThreadMethodEntry?

此外,Finalizer隊列上的所有根GC對象都是實例System.Windows.Forms.Control + ThreadMethodEntry名爲「caller」的對象。我發現它涉及到多線程的用戶界面交互,但我除此之外不太瞭解。原諒我表面上的懶惰並承認無知,但這些資源全都埋在供應商的組成部分。我正在與供應商討論這些問題,但我需要一些方向讓我加快談話速度。你能指出我對ThreadMethodEntry最有用的定義嗎?任何軼事建議?

此外,我是否應該關心終結器隊列上的這些對象?

更新:這對​​3210有幫助。

回答

14

終結器隊列包含所有定義了終結器方法的對象。回想一下,終結器是一種收集非託管資源(如句柄)的方法。當垃圾收集器收集垃圾時,它將帶有終結器的任何對象移動到終結器隊列中。在稍後的某個時刻 - 根據內存壓力,GC啓發式和月球的相位 - 當垃圾收集器決定收集這些對象時,它沿着隊列走下來並運行終結器。

已經在過去的內存泄漏的工作,看到一大堆供應商的對象終結隊列可能是草率的代碼,但它並不表示內存泄漏。通常,良好的代碼將公開一個Dispose方法,該方法將收集託管資源和非託管資源,並通過GC.SuppressFinalize()將其自身從終結器隊列中移除。因此,如果供應商的對象確實實現了Dispose方法,並且您的代碼沒有調用它,那麼這可能會導致終結器隊列中的一堆對象。

您是否嘗試過在時間上創造了兩個點之間的螞蟻快照,並比較它們之間創建的對象?這可以幫助您識別任何被泄露的管理對象。

另外,如果你想看看記憶消失時終結器運行,試試這個只是測試:

 
System.GC.Collect(); 
System.GC.WaitForPendingFinalizers(); // this method may block while it runs the finalizers 
System.GC.Collect(); 

我不建議正常運行這段代碼。如果你剛剛完成了大量工作並創建了大量垃圾,則可能需要運行它。例如,在我們的應用程序中,我們的一個函數可以創建大約350 MB的垃圾,在關閉MDI窗口後浪費掉。由於這已知會留下大量垃圾,我們手動強制垃圾收集。

另請注意,在基本Windows.Forms代碼中有一個低級屬性緩存,它將保留在上次打開的模式對話框中。這可能是內存泄漏的根源。擺脫這種引用的一個可靠方法是強制出現另一個簡單的對話框,然後運行上面的GC代碼。

+0

謝謝你的出色答案,保羅。這是我正在談論的對象引用圖,在清理資源之後查看第二個快照中的新對象。圖中實現IDisposable的所有對象都有一個工具提示,說「已爲此對象調用Dispose()」,但所選對象沒有此工具提示。 – flipdoubt 2009-08-12 21:24:54

+2

關於ThreadMethodEntry的注意事項:我認爲它們用於UI線程的任何調用。每個Control對象都有一個ThreadMethodEntry類型的線程回調隊列。一個回調出隊一個ThreadMethodEntry並運行它。 每個ThreadMethodEntry對象都有一堆內部字段。檢查這些字段可能會幫助您找出哪些供應商的對象正在調用。我不記得是否可以從ANTS獲取這些信息,但我知道你可以通過WinDbg.dll和sos.dll(託管調試器擴展)。看看「方法」委託和「調用者」控件。 – 2009-08-12 22:04:41

+0

另請注意,ThreadMethodEntry對象實現了一個終結器,但它們沒有Dispose方法。當他們完成時,他們也會被移動到終結者隊列中。 – 2009-08-12 22:05:17

1

終結隊列一種情況,即不再使用的對象實例等待由GC定稿的隊列。此隊列中的所有對象都將被最終確定,並且您的內存泄漏可能不會直接來自其中一個對象。但是,其中一個對象可能不會釋放其所有非託管資源。

ThreadMethodEntry類是IAsyncResult的實現,此類的實例通常在調用異步操作時創建,例如使用Invoke更新UI或使用Begin */End *方法。

0

Here's一個很好的博客文章,其中描述了類似的問題。在技​​術層面上,您可以使用SOS.dll(博客文章描述)和Sosex.dll來幫助您找出爲什麼這些ThreadMethodEntry對象在內存中閒置。這些WinDbg擴展中有一些命令可以跟蹤其他對象在內存中引用特定對象的內容。