2010-10-20 41 views
3

我正在研究一些需要非常低的延遲並推送大量內存的應用程序,並正在對一些應用程序進行測試。分配一個列表ad-hoc與預分配和清除列表執行。 我期待測試運行時預分配內存的執行速度要快得多,但令我驚訝的是它們實際上稍慢(當我讓測試運行10分鐘時,平均差異大約爲400ms)。.NET預分配內存vs臨時分配

下面是測試代碼,我用:

class Program 
{ 
    private static byte[] buffer = new byte[50]; 
    private static List<byte[]> preAlloctedList = new List<byte[]>(500); 

    static void Main(string[] args) 
    { 
     for (int k = 0; k < 5; k++) 
     { 
      Stopwatch sw = new Stopwatch(); 
      sw.Start(); 

      for (int i = 0; i < 1000000; i++) 
      { 
       List<byte[]> list = new List<byte[]>(300); 

       for (int j = 0; j < 300; j++) 
       { 
        list.Add(buffer); 
       } 
      } 

      sw.Stop(); 
      Console.WriteLine("#1: " + sw.Elapsed); 
      sw.Reset(); 
      sw.Start(); 

      for (int i = 0; i < 1000000; i++) 
      { 
       for (int j = 0; j < 300; j++) 
       { 
        preAlloctedList.Add(buffer); 
       } 

       preAlloctedList.Clear(); 
      } 
      sw.Stop(); 
      Console.WriteLine("#2: " + sw.Elapsed); 
     } 

     Console.ReadLine(); 
    } 
} 

現在,什麼是真正有趣的,我跑並排性能監視器側,看到下面的圖案看起來像我的預期:

綠色=第0級集合
藍色=分配的字節/秒
紅色=%在GC時間

下面的控制檯應用程序顯示#1和試驗運行時#2
alt text

所以,我的問題是,爲什麼測試#1比#2更快?
顯然,我寧願在我的應用程序中測試#2的perfmon統計數據,因爲基本上沒有內存壓力,沒有GC集合等,但#1似乎稍快一點?
List.Clear()會帶來多大的開銷嗎?

感謝,

湯姆

編輯 我做了另外一個測試,用相同的設置,但運行與服務器GC的應用啓用,目前#2變稍快 alt text

回答

4

我懷疑測試#1更快的原因是垃圾收集發生在單獨的線程上,並且分配的開銷低於額外的List<T>.Clear調用。由於這些列表都不是很大(每個只有300個引用),並且它們都是在緊密循環中創建和取消的,所以它們通常都會保留在Gen 0中。

我在分析過程中注意到了這一點過去 - 重複使用List<T>並對其調用Clear通常比重新分配要慢。 Clear()實際上會清除內部數組以及重置列表的參數,我認爲這些參數比列表的初始分配開銷(略)多。

但是,在我看來,這個例子實際上只是表明.NET中的GC非常非常高效。

+0

非常感謝您的回覆。你會選擇哪一個選項,但在非常相似的生產場景中?現在,有趣的是,當我啓用服務器GC運行相同的應用程序時,#2實際上變得更快。我更新了這篇文章,並附上截圖 – TJF 2010-10-20 19:37:29

+0

@Tom:服務器模式以更高的延遲爲代價提高了整體吞吐量。哪個更好取決於你。話雖如此,我通常只在我的生產環境中使用#1 - 代碼更乾淨,而且它的整體性能更好。 – 2010-10-20 20:01:21

3

List.Clear()會帶來那麼多開銷嗎?

是的,與(單個)GC.Collect(0)相比,對Clear()進行幾千次調用可能會更慢。

據我所知,dotNet內存系統在分配/釋放短暫內存塊方面速度非常快。

但要小心從這個簡單的測試結果到您的真實應用程序。

+0

我看了清單的實現和Clear()做了一個extern調用。你碰巧知道了什麼成就?我可以使用Clear()只實現一個List的實現,只重置大小字段 – TJF 2010-10-20 19:48:40

+0

從不知道,這是Clear所做的:根據元素類型,將數組中元素的範圍設置爲零,爲假或爲空。 – TJF 2010-10-20 19:50:37

+0

@Tom:您必須清除數組,否則您將保留所有元素的根,因此GC無法收集它們。一般來說,我會盡量避免像這樣重新發明輪子...... – 2010-10-20 20:02:16