我已經穿過其中的垃圾回收似乎是相同的代碼之間的不同表現運行寫成一個單元測試VS寫在一個控制檯應用程序的Main
方法的情況下絆倒。我想知道這種差異背後的原因。不同的垃圾收集行爲
在這種情況下,我和同事在分配垃圾收集事件處理程序的效果上存在分歧。我認爲比簡單地給他發送一個鏈接到highly rated SO answer的示例會更好。因此我寫了一個簡單的演示作爲單元測試。
我的單元測試顯示事情的工作,因爲我說他們應該。但是,我的同事編寫了一個控制檯應用程序,顯示事情正在按照他的方式工作,這意味着GC未按照我對Main
方法中的本地對象的預期發生。只需將我的測試代碼移動到控制檯應用程序項目的Main
方法中,我就能夠重現他所看到的行爲。
我想知道的是爲什麼GC在控制檯應用程序的Main
方法中運行時似乎沒有按預期收集對象。通過提取方法,以便調用GC.Collect
和超出範圍的對象以不同的方法發生,預期的行爲被恢復。
這些是我用來定義我的測試的對象。只有一個事件對象和一個爲事件處理程序提供合適方法的對象。兩者都有終結者設置一個全局變量,這樣你就可以知道他們什麼時候被收集了。
private static string Log;
public const string EventedObjectDisposed = "EventedObject disposed";
public const string HandlingObjectDisposed = "HandlingObject disposed";
private class EventedObject
{
public event Action DoIt;
~EventedObject()
{
Log = EventedObjectDisposed;
}
protected virtual void OnDoIt()
{
Action handler = DoIt;
if (handler != null) handler();
}
}
private class HandlingObject
{
~HandlingObject()
{
Log = HandlingObjectDisposed;
}
public void Yeah()
{
}
}
這是我測試(NUnit的),其通過:
[Test]
public void TestReference()
{
{
HandlingObject subscriber = new HandlingObject();
{
{
EventedObject publisher = new EventedObject();
publisher.DoIt += subscriber.Yeah;
}
GC.Collect(GC.MaxGeneration);
GC.WaitForPendingFinalizers();
Thread.MemoryBarrier();
Assert.That(Log, Is.EqualTo(EventedObjectDisposed));
}
//Assertion needed for foo reference, else optimization causes it to already be collected.
Assert.IsNotNull(subscriber);
}
GC.Collect(GC.MaxGeneration);
GC.WaitForPendingFinalizers();
Thread.MemoryBarrier();
Assert.That(Log, Is.EqualTo(HandlingObjectDisposed));
}
我在一個新的控制檯應用程序的Main
方法粘貼在主體的上方,並且被轉換的Assert
調用Trace.Assert
調用。兩個平等聲明失敗,然後失敗。如果你想要的話,結果Main方法的代碼是here。
我確實認識到,GC發生時應該被視爲非確定性的,並且通常應用程序不應該關心其發生的時間。 在所有情況下,代碼都是以發佈模式編譯並針對.NET 4.5。
編輯:其他的事情我想
- 使得測試方法
static
因爲NUnit的支持;測試仍然有效。 - 我也嘗試將整個Main方法提取到程序中的實例方法並調用它。兩個斷言仍然失敗。
- 歸屬
Main
與[STAThread]
或[MTAThread]
在案件this作出了區別。兩個斷言仍然失敗。 - 基於@武果汁的建議:
- 我引用的NUnit的控制檯應用程序,這樣我可以使用NUnit的斷言,他們失敗了。
- 我試着對測試,測試類,
Main
方法以及包含Main
方法的靜態類進行各種更改。不用找了。 - 我試着讓Test類是靜態的,而包含
Main
方法的類是靜態的。不用找了。
當你使用帶默認參數的'GC.Collect()'並且不指定代時,結果是什麼? – 2013-04-21 15:57:39
@ Moo-Juice測試依然通過,控制檯應用程序斷言仍然失敗,從控制檯應用程序中提取方法仍然會導致斷言成功。 – vossad01 2013-04-21 16:04:20
我想知道這種差異是否是由於'Main'處於靜態類中的事實......我不確定,但除此之外,'Trace'與'Assert'的行爲我沒有想法。你是否嘗試過在靜態環境中運行測試? – 2013-04-21 16:21:45