2012-09-02 32 views
-2

我們有一個巨大的程序,產生了太多的垃圾。這會損害性能,每秒產生數以千計的軟頁面錯誤,減少延遲,損害吞吐量等。字典的任何現有實現都是無垃圾的?

其中一個主要的元兇是System.Collections.Generic.Dictionary,所以我們想用一個版本替換它,分配10,000個條目,然後重新使用這些條目。

是否有任何現有的Dictionary實現允許預分配條目,並且不會在運行時產生垃圾?

+4

您是否嘗試過使用帶有10,000的'Dictionary'構造函數作爲它的容量? http://msdn.microsoft.com/en-us/library/tk84bxf4.aspx –

+0

什麼是TKey和TValue,並且您是使用通用API還是非通用API來訪問它? –

+0

字典以O(log N)速率增長。它不能確定的是,預定義元素的數量將幫助你處理垃圾收集問題。遇到這些問題時,重新審視您的策略是明智的。分配這麼多的字典實例是否真的很困難? – Polity

回答

2

我們最終決定不使用無垃圾詞典,因爲它不會影響整體GC。

爲了記錄,這裏是一個無垃圾字典的實現。它的記憶力很強,但效果很好。

要使用實例化一個新字典,併爲潛在整數鍵提供足夠的插槽。例如,如果主整數鍵可以0到50000之間的範圍,那麼你就需要通過50,000當實例吧:

MyIntegerKeyDictionary = new MyIntegerKeyDictionary<int, MyClass>(50000); 

如果鍵的範圍可以從20萬至25萬5萬潛在實例化它鍵,它會自動「重新定位」鍵(基於它看到的第一個鍵),因此它可以從200,000到250,000。

using System; 
using System.Collections.Concurrent; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Threading; 
using MyLogType; 

namespace MyHelper 
{ 
/// <summary> 
/// NOTE: Non thread safe, only run this individually. 
/// </summary> 
/// <typeparam name="T">Type of item we are adding to the dictionary.</typeparam> 
public class MyIntegerKeyDictionary<T> where T : class 
{ 
    /// <summary> 
    /// Array in which we store the entries. 
    /// </summary> 
    volatile private T[] ArrayToUse; 

    /// <summary> 
    /// Allows us to check the maximum size, just in case. 
    /// </summary> 
    private readonly int SizeInternal; 

    /// <summary> 
    /// Keeps track of the current number of items in the dictionary. 
    /// </summary> 
    public int Count = 0; 

    /// <summary> 
    /// Base number. For numbers that start with a huge base, this allows the index to work without allocating megabytes of memory. 
    /// </summary> 
    private int BaseNumberToAdd { get; set; } 

    /// <summary> 
    /// Constructor. 
    /// </summary> 
    /// <param name="Size">Size of the dictionary.</param> 
    public MyIntegerKeyDictionary(int Size) 
    { 
     // Create the array to hold n number of items. 
     ArrayToUse = new T[Size]; 

     // We must touch all of these entries, to force page faults now (rather than later). 
     for (int i = 0; i < ArrayToUse.Length; i++) 
     { 
      ArrayToUse[i] = null; 
     } 
     BaseNumberToAdd = int.MinValue; 

     this.SizeInternal = Size; 
    } 

    /// <summary> 
    /// Add an item. 
    /// </summary> 
    /// <param name="Key">Key.</param> 
    /// <param name="Value">Value.</param> 
    /// <returns>True if the item was added, false if not.</returns> 
    public bool TryAdd(int Key, T Value) 
    { 
     if (BaseNumberToAdd == int.MinValue) 
     { 
      BaseNumberToAdd = Key; 
      //Console.Write(string.Format("{0}Message W20120907-3751. TryAdd. Adding first item {1}.\n", 
      //MyLog.NPrefix(), Key)); 
     } 
     Key = Key - BaseNumberToAdd; 

     if (Key < 0) 
     { 
      Console.Write(string.Format("{0}Warning W20120907-3750. TryAdd. Attempted to add a key with index {1} which is < 0.\n", 
       MyLog.NPrefix(), Key)); 
      return false; 
     } 

     if (Key >= this.SizeInternal) 
     { 
      Console.Write(string.Format("{0}Warning W20120907-3756. TryAdd. Attempted to add a key with index {1} which is > max {2}\n", 
       MyLog.NPrefix(), Key, this.SizeInternal)); 
      return false; 
     } 

     if (ArrayToUse[Key] == null) 
     { 
      Interlocked.Increment(ref Count); 
     } 

     ArrayToUse[Key] = Value; 
     return true; 
    } 

    /// <summary> 
    /// Remove an item from the dictionary. 
    /// </summary> 
    /// <param name="Key">Key that we want to remove.</param> 
    /// <returns>True if the item could be removed, false if not.</returns> 
    public bool TryRemove(int Key) 
    { 
     if (BaseNumberToAdd == int.MinValue) 
     { 
      Console.Write(string.Format("{0}Warning W20120907-8756. TryRemove. Attempted to remove an item without any items in the dictionary yet {1}.\n", 
       MyLog.NPrefix(), Key)); 
      return false; 
     } 
     Key = Key - BaseNumberToAdd; 


     if (Key < 0) 
     { 
      Console.Write(string.Format("{0}Warning W20120907-9756. TryRemove. Attempted to remove a key with index {1} which is < 0.\n", 
       MyLog.NPrefix(), Key)); 
      return false; 
     } 

     if (Key >= this.SizeInternal) 
     { 
      Console.Write(string.Format("{0}Warning W20120907-6756. TryRemove. Attempted to remove a key with index {1} which is > max {2}\n", 
       MyLog.NPrefix(), Key, this.SizeInternal)); 
      return false; 
     } 

     if (ArrayToUse[Key] != null) 
     { 
      Interlocked.Decrement(ref Count); 
     } 

     ArrayToUse[Key] = null; 

     return true; 
    } 


    /// <summary> 
    /// Indexer. 
    /// </summary> 
    /// <param name="key">Key.</param> 
    /// <returns>Value.</returns> 
    public T this[int key] 
    { 
     get 
     { 
      T valueToReturn; 
      TryGetValue(key, out valueToReturn); 
      return valueToReturn; 
     } 
    } 

    /// <summary> 
    /// Attempt to get the value. 
    /// </summary> 
    /// <param name="Key">Key.</param> 
    /// <param name="Value">Value.</param> 
    /// <returns>True if the value exists, false if not.</returns> 
    public bool TryGetValue(int Key, out T Value) 
    { 
     Value = null; 
     if (BaseNumberToAdd == int.MinValue) 
     { 
      Console.Write(string.Format("{0}Warning W20120907-8756. TryGetValue. Attempted to retrieve an item without any items in the dictionary yet {1}.\n", 
       MyLog.NPrefix(), Key)); 
      return false; 
     } 
     Key = Key - BaseNumberToAdd; 
     if (ArrayToUse[Key] == null) 
     { 

      return false; 
     } 

     Value = ArrayToUse[Key]; 
     return true; 
    } 

    /// <summary> 
    /// Checks to see if the key exists. 
    /// </summary> 
    /// <param name="Key">Key index.</param> 
    /// <returns>True if the item exists, false if not.</returns> 
    public bool ContainsKey(int Key) 
    { 
     if (Key == 0) 
     { 
      Console.Write(string.Format("{0}Warning W20120907-1914. ContainsKey. Have not rebased yet. Ignoring query for ContainsKey(0).\n", 
       MyLog.NPrefix())); 
      return false; 
     } 

     if (BaseNumberToAdd == int.MinValue) 
     { 
      Console.Write(string.Format("{0}Warning W20120907-8756. ContainsKey. Attempted to check if Key {1} exists, however BaseNumber is not set yet.\n", 
       "", Key)); 
      return false; 
     } 
     Key = Key - BaseNumberToAdd; 

     if (Key < 0) 
     { 
      Console.Write(string.Format("{0}Warning W20120907-8756. ContainsKey. Key = {1} which is < 0.\n", 
       "", Key)); 
      return false; 
     } 

     if (Key >= this.SizeInternal) 
     { 
      MyLogAsync.LogWarning(string.Format("{0}Warning W20120907-5756. ContainsKey. Key({1}) >= this.SizeInternal ({2}).\n", 
       MyLog.NPrefix(), Key, this.SizeInternal)); 
      return false; 
     } 

     if (ArrayToUse[Key] == null) 
     { 
      return false; 
     } 
     return true; 
    } 
    /* 
    private bool CheckKeyBounds(int Key, string description) 
    { 
     if (Key < 0) 
     { 
      MyLogAsync.LogWarning(string.Format("{0}Warning W20120907-8756. {1}. Attempted to add a key with index {2} which is < 0.\n", 
       MyLog.NPrefix(), description, Key)); 
     } 

     if (Key >= this.SizeInternal) 
     { 
      MyLogAsync.LogWarning(string.Format("{0}Warning W20120907-5756. {1}. Attempted to add a key with index {2} which is > max {3}\n", 
       MyLog.NPrefix(), description, Key, this.SizeInternal)); 
      return false; 
     } 
    } 
    */ 
} 
} 
相關問題