2010-08-13 52 views
3

我正在嘗試使用.NET 4編寫單元測試,以確保某個代碼運行後可以垃圾收集對象。在Java中,我將使用assertGC來確保收集弱引用。我怎樣才能爲.NET編寫這種類型的測試?Java的assertGC的.NET版本:單元測試內存泄漏

我已經嘗試了保留WeakReference的對象,並調用GC.Collect(),但正如你所期望的,有時我的對象被收集,有時它不是。請注意,這是用於單元測試,而不是生產代碼。我不想在我的真實代碼庫中使用GC.Collect()。

我使用C#,但同樣的答案也會對VB.NET有好處。

+2

你爲什麼單元測試此,它聽起來就像你正在編寫爲.NET Framework的內存管理單元測試。你究竟在做什麼測試? – 2010-08-13 10:47:08

+0

@Ben Robinson,我正在進行單元測試,我不是不小心從一個靜態變量(例如緩存)引用我的對象,並且該對象可以被垃圾回收。我正在使用的系統有一個龐大的代碼庫和大量的可配置模塊,可能會導致我的對象被其他人編寫的代碼引用。 – Andrew 2010-08-13 10:48:21

+0

[雷蒙德陳](http://blogs.msdn.com/b/oldnewthing/)目前有他的CLR周,他的話題本週聽起來有點類似於你的問題。 – Joey 2010-08-13 10:56:19

回答

0

看起來這是不可能的,在與.NET 4的時刻雖然這是不可能知道的對象不會被垃圾收集是否可以(如已對它的引用),有沒有辦法確定性地知道對象是否可以被垃圾收集。

使用WeakReference或finaliser(並調用GC.Collect())可能收集該對象,但除非它在第0代中,否則它有一個公平的機會。

參考文獻:

1

試試這個:

運行5分鐘紮實,仍然沒有例外......你確定你的代碼不引用你的對象的地方?

using System; 

internal class Program 
{ 
    private static void Main(string[] args) 
    { 
     int cnt = 0; 
     while (true) 
     { 
      ++cnt; 
      bool gced = false; 
      Action handler =() => gced = true; 
      new Foo(handler); 
      GC.Collect(); 
      GC.WaitForPendingFinalizers(); 
      Console.Out.WriteLine("{0} : {1}", cnt, gced); 
      if (!gced) 
      { 
       throw new Exception("WTF?"); 
      } 
     } 
    } 
} 
class Foo 
{ 
    private readonly Action _onFinalized; 

    public Foo(Action finalized) 
    { 
     _onFinalized = finalized; 
    } 

    ~Foo() 
    { 
     if (_onFinalized != null) _onFinalized(); 
    } 
} 
+0

感謝您的答案。我修改了我的對象以包含您的字段,構造函數和終結器。當我在我的機器上運行此測試時,終結器(因此Action)並不總是運行。在我的機器上,只需一個按鈕即可運行測試,它在第一次和第二次在一個進程中運行,但不會在第三次運行。第四次,第三次的對象被定稿,但新的對象不是!單元測試適用於我的機器,但不適用於構建機器。 GC.Collect()不會觸發終結器。 – Andrew 2010-08-13 11:44:28

+0

那麼waitforpendinfinalizer呢? 如果您處於調試模式,則可能由調試vizualizers持有對'a'的引用... – 2010-08-13 12:22:27

+0

代碼全部使用調試標誌進行編譯,但是當調試器未連接到應用程序時,問題仍然存在。此外 - 這個問題是間歇性的 - 它有時會起作用。 – Andrew 2010-08-13 13:16:44