2012-09-02 3 views
-2

우리는 너무 많은 쓰레기를 생성하는 엄청난 프로그램을 가지고 있습니다. 이는 매초마다 수천 건의 소프트 페이지 오류를 생성하고 지연 시간을 줄이며 처리량을 저하시킵니다.Dictionary의 기존 구현에 쓰레기가 없습니다.

주된 원인 중 하나는 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 (로그 N) 비율로 증가합니다. 요소의 양을 미리 정의하면 가비지 수집 문제를 해결하는 데 도움이 될 것입니다. 이러한 문제가 발생하면 전략을 재검토하는 것이 좋습니다. 너무 많은 사전 인스턴스를 할당하는 것이 정말로 필요합니까? – Polity

답변

2

전체 GC에 그다지 영향을 미치지 않았으므로 결국에는 가비지없는 사전을 사용하지 않기로 결정했습니다.

기록을 위해 다음은 가비지없는 사전의 구현입니다. 배고픈 기억이지만 잘 돌아 간다.

잠재적 정수 키에 충분한 슬롯을 사용하여 새 사전을 인스턴스화합니다. 키가 20 만에서 25 만까지 다양 할 수 있다면

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

, 50,000 잠재력을 인스턴스화 : 당신이 그것을 인스턴스화 할 때 예를 들어, 기본 정수 키가 0과 50000 사이의 범위 수 있다면, 당신은 5 만 합격해야합니다 키를 누르면 자동으로 "리베이스 (rebase)"되어 첫 번째 키를 기준으로 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; 
     } 
    } 
    */ 
} 
} 
관련 문제