C# 字典的任何现有实现都是无垃圾的吗?

C# 字典的任何现有实现都是无垃圾的吗?,c#,.net,visual-studio,.net-4.0,C#,.net,Visual Studio,.net 4.0,我们有一个巨大的程序,产生了太多的垃圾。这会影响性能,每秒产生数千个软页面错误,减少延迟,影响吞吐量,等等 罪魁祸首之一是System.Collections.Generic.Dictionary,因此我们希望将其替换为一个版本,允许我们预先分配10000个条目,然后动态重用这些条目 是否有任何现有的字典实现允许预先分配条目,并且不会在运行时生成垃圾?我们最终决定不使用无垃圾字典,因为它不会对整个GC造成太大影响 下面是一个无垃圾字典的实现。它的内存不足,但它工作得很好 若要使用,请实例化一个新

我们有一个巨大的程序,产生了太多的垃圾。这会影响性能,每秒产生数千个软页面错误,减少延迟,影响吞吐量,等等

罪魁祸首之一是
System.Collections.Generic.Dictionary
,因此我们希望将其替换为一个版本,允许我们预先分配10000个条目,然后动态重用这些条目


是否有任何现有的
字典
实现允许预先分配条目,并且不会在运行时生成垃圾?

我们最终决定不使用无垃圾字典,因为它不会对整个GC造成太大影响

下面是一个无垃圾字典的实现。它的内存不足,但它工作得很好

若要使用,请实例化一个新字典,其中有足够的插槽用于放置潜在的整数键。例如,如果主整型键的范围在0到50000之间,则在实例化时需要传入50000:

MyIntegerKeyDictionary = new MyIntegerKeyDictionary<int, MyClass>(50000);
MyIntegerKeyDictionary=新的MyIntegerKeyDictionary(50000);
如果密钥的范围在200000到250000之间,请使用50000个潜在密钥对其进行实例化,它将自动“重新设置”密钥的基础(基于它看到的第一个密钥),使其范围在200000到250000之间

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;
        }
    }
    */
}
}
使用系统;
使用System.Collections.Concurrent;
使用System.Collections.Generic;
使用System.Linq;
使用系统文本;
使用系统线程;
使用MyLogType;
名称空间MyHelper
{
/// 
///注意:非线程安全,仅单独运行。
/// 
///我们要添加到词典中的项的类型。
公共类MyIntegerKeyDictionary,其中T:class
{
/// 
///存储条目的数组。
/// 
易失性私有T[]阵列使用;
/// 
///允许我们检查最大尺寸,以防万一。
/// 
私有只读int-SizeInternal;
/// 
///跟踪词典中的当前项数。
/// 
公共整数计数=0;
/// 
///基数。对于以大基数开始的数字,这允许索引在不分配兆字节内存的情况下工作。
/// 
private int BaseNumberToAdd{get;set;}
/// 
///构造器。
/// 
///字典的大小。
公共MyIntegerKeyDictionary(整数大小)
{
//创建数组以容纳n个项目。
ArrayToUse=新的T[尺寸];
//我们必须触摸所有这些条目,以强制现在(而不是以后)出现页面错误。
for(int i=0;i=this.SizeInternal)
{
Console.Write(string.Format(“{0}警告W20120907-3756.TryAdd.试图添加索引{1}大于max{2}的键\n”,
MyLog.NPrefix(),Key,this.SizeInternal));
返回false;
}
if(ArrayToUse[Key]==null)
{
联锁增量(参考计数);
}
ArrayToUse[键]=值;
返回true;
}
/// 
///从字典中删除一项。
/// 
///我们要删除的密钥。
///如果可以删除该项,则为True;如果不能,则为false。
公共bool TryRemove(int键)
{
if(BaseNumberToAdd==int.MinValue)
{
Console.Write(string.Format(“{0}警告W20120907-8756.TryRemove)。试图删除字典中没有任何项的项{1}。\n”,
MyLog.NPrefix(),Key));
返回false;
}
Key=Key-BaseNumberToAdd;
如果(键<0)
{
Console.Write(string.Format(“{0}警告W20120907-9756.TryRemove)。试图删除索引{1}小于0的键。\n”,
MyLog.NPrefix(),Key));
返回false;
}
如果(键>=this.SizeInternal)
{
Console.Write(string.Format(“{0}警告W20120907-6756.TryRemove)。试图删除索引为“{1}”且大于max{2}”的键\n”,
MyLog.NPrefix(),Key,this.SizeInternal));
返回false;
}
if(数组使用[Key]!=null)
{
联锁。减量(参考计数);
}
ArrayToUse[Key]=null;
返回true;
}
/// 
///索引器。
/// 
///钥匙。
///价值观。
此[int-key]的公共密钥
{
得到
{
T值返回;
TryGetValue(键,输出值返回);
返回值返回;
}
}
/// 
///尝试获取该值。
/// 
///钥匙。
///价值观。
///如果该值存在,则为True;如果不存在,则为false。
公共bool TryGetValue(int键,out T值)
{
值=空;
if(BaseNumberToAdd==int.MinValue)
{
Console.Write(string.Format(“{0}警告W20120907-8756.TryGetValue)。试图检索字典中尚未包含任何项的项{1}。\n”,
MyLog.NPrefix(),Key));
返回false;
}
Key=Key-BaseNumberToAdd;
if(ArrayToUse[Key]==null)
{
返回false;
}
值=数组使用[键];