2009-04-14 100 views
12

GC.Collect似乎在後臺線程中啓動垃圾回收,然後立即返回。我如何同步運行GC.Collect - 即等待垃圾收集完成?運行GC.Collect同步

這是在NUnit測試的上下文中。我嘗試將gcConcurrent設置添加到我的測試程序集的app.config文件中,並且我嘗試了與nunit.exe.config相同的設置。沒有任何影響 - 當我調試時,我仍然可以看到終結器在「GC終結器線程」上運行,而不是稱爲GC.Collect(NUnit的「TestRunnerThread」)的線程,並且兩個線程都同時運行。

背景:我想我的測試失敗,如果他們泄漏(不要調用Dispose)一個特定的類。所以我添加了一個終結器給那個設置了靜態wasLeaked標誌的類;那麼我的測試TearDown調用GC.Collect(),然後拋出if wasLeaked爲真。但它不是確定性地失敗,因爲當它讀取wasLeaked時,終結器通常還沒有被調用。 (它失敗以後的某個測試取而代之的是,垃圾收集終於結束了。)

回答

12

終結器在專用的,高優先級的後臺線程上運行。從您的文章的背景,據我瞭解,你可以簡單地做

GC.Collect(); 
GC.WaitForPendingFinalizers(); 

Collect()將安排最後定稿任何非根實例,然後該線程將等待終結器線程來完成。

5

您可以使用GC.RegisterForFullGCNotification,觸發全面收集與GC.Collect(GC.MaxGeneration),然後GC.WaitForFullGCCompleteGC.WaitForPendingFinalizers方法,但要確保只在您的測試中使用此,他們不應該用於生產代碼。

+0

文檔說WaitForFullGCApproach和WaitForFullGCComplete應該總是一起使用。當我明確觸發GC時,如何等待GC方法?你有這樣的代碼示例嗎? – 2009-04-14 19:06:17

+0

對不起,遲交的答案。這裏有一個很好的解釋和示例,它應該或多或少地適用於您的代碼: http://msdn.microsoft.com/en-us/library/cc713687.aspx 您可能想要選擇您的方法通知限制,以便你基本上會立即得到通知。 – Lucero 2009-04-14 22:22:36

2

這樣做的一個更簡單/更好的方法可能是使用模擬並檢查顯式調用Dispose的期望。

實施例使用RhinoMocks

public void SomeMethodTest() 
{ 
    var disposable = MockRepository.GenerateMock<DisposableClass>(); 

    disposable.Expect(d => d.Dispose()); 

    // use constructor injection to pass in mock `DisposableClass` object 
    var classUnderTest = new ClassUnderTest(disposable); 

    classUnderTest.SomeMethod(); 

    disposable.VerifyAllExpectations(); 
} 

如果該方法需要創建,然後處置的對象,然後我會用和注射工廠類,其能夠創建模擬對象。下面的例子在工廠使用stub,因爲它不是我們在測試中測試的東西。

public void SomeMethod2Test() 
{ 
    var factory = MockRepository.Stub<DisposableFactory>(); 
    var disposable = MockRepository.GenerateMock<DisposableClass>(); 

    factory.Stub(f => f.CreateDisposable()).Return(disposable);   
    disposable.Expect(d => d.Dispose()); 

    // use constructor injection to pass in mock factory 
    var classUnderTest = new ClassUnderTest(factory); 

    classUnderTest.SomeMethod(); 

    disposable.VerifyAllExpectations(); 
} 
+0

這是測試確定性版本的好方法,但不測試終結器代碼是否正常工作。因此,Joe可能希望使用兩種方法,具體取決於他想要準確測試的內容。 – Lucero 2009-04-14 18:36:53

2

終結器總是在單獨的線程上運行,無論您是否使用併發GC。如果您想確保終結器已經運行,請嘗試使用GC.WaitForPendingFinalizers