正在寻找将大量对象加载到.NET中IDictionary的技术

正在寻找将大量对象加载到.NET中IDictionary的技术,.net,algorithm,collections,memory-management,.net,Algorithm,Collections,Memory Management,我需要将大约600万个对象加载到字典中。我所遇到的问题是,只需将它们添加到字典中,然后在字典分配新数组和取消分配现有数组时,将它们构造为内存碎片。最后,由于空闲内存的碎片化,我只能将200万个内存加载到内存中。问题是我不知道这些物品的实际数量。这完全取决于用户的输入 我的不太完美的解决方案是: 1.创建所有对象后,使用链接列表存储这些对象。我这样做是因为链接列表不需要连续的可用空间 2.创建具有所需确切大小的字典,因此无需重新分配内部字典数组 3.将对象复制到字典中。这样,我最多可以加载300万

我需要将大约600万个对象加载到字典中。我所遇到的问题是,只需将它们添加到字典中,然后在字典分配新数组和取消分配现有数组时,将它们构造为内存碎片。最后,由于空闲内存的碎片化,我只能将200万个内存加载到内存中。问题是我不知道这些物品的实际数量。这完全取决于用户的输入

我的不太完美的解决方案是:
1.创建所有对象后,使用链接列表存储这些对象。我这样做是因为链接列表不需要连续的可用空间
2.创建具有所需确切大小的字典,因此无需重新分配内部字典数组
3.将对象复制到字典中。这样,我最多可以加载300万

有没有关于如何改进的建议?或者,您是否知道在内部不使用数组的免费IDictionary实现

多谢各位

更新:根据值类型,我的键是固定长度的字符串。通常约8个字符长,但最多可达20个字符。而且,随着关键帧长度的增加,项目的总可能数量会爆炸。幸运的是,目前项目的最大数量为1200万件。该值是一个类类型,每个实例的总大小约为90-120字节


这是一个在32位windows上运行的winforms应用程序。而且,我的典型主机有2G内存。在消耗大量空间的应用程序中存在大量内存浪费。不幸的是,我现在无法解决这些问题。

600万个对象似乎需要保存在程序内存中,您可能不需要同时加载它们


将其置于应用程序之外是否有意义?可能在数据库中(可能使用类似SQLite或SQLServer Compact的格式)?

整个碎片问题可以通过使用容量来解决:

var d = new Dictionary<int, string>(expectedCapacity);
var d=新字典(预期容量);
应悲观地计算预期容量
,并留出一点空间

但是当它与引用类型和/或小值类型一起使用时,这应该不会有太大的区别。我想你应该重新检查一下你的诊断

碎片只是大型对象堆上的一个问题,600万K,V对(~6M*20=120MB)不应该这样做

但要知道字典是如何增长的:当它满了的时候,它会翻倍。因此,当装载(略多于)800万件物品时,最终的容量可能达到1600万件,在LOH上还放置了8米、4米、2米等区块。
那可能会引起一场爆炸


因此,提前估计物品的数量是非常值得的

分区有帮助吗

我使用了一种方法,使用dictionary键的
GetHashCode()
的异或计算字节哈希,将dictionary划分为256个较小的子字典。基本上,您有一个内部
词典
,它保存外部
IDictionary
的值

如果您从这样一个大型字典类开始:

public class LargeDictionary<K, V> : IDictionary<K, V>
{
    private readonly Dictionary<byte, Dictionary<K, V>> _inner =
            new Dictionary<byte, Dictionary<K, V>>();

    private Dictionary<K, V> GetInner(K key)
    {
        var bs = BitConverter.GetBytes(key.GetHashCode());
        var prekey = (byte)(bs[0] ^ bs[1] ^ bs[2] ^ bs[3]);
        if (!_inner.ContainsKey(prekey))
        {
            _inner.Add(prekey, new Dictionary<K, V>());
        }
        return _inner[prekey];
    }

    /* See below */

}
公共类大型词典:IDictionary
{
专用只读词典=
新字典();
私有字典GetInner(K密钥)
{
var bs=BitConverter.GetBytes(key.GetHashCode());
var prekey=(字节)(bs[0]^bs[1]^bs[2]^bs[3]);
如果(!\u内部容器(预键))
{
_Add(prekey,newdictionary());
}
返回内部[预键];
}
/*见下文*/
}
您是否能够从这一点开始,并可能重建内部字典的某些部分,以便在运行时回收内存

以下是本课程的其他内容:

    public void Add(K key, V value)
    {
        this.GetInner(key).Add(key, value);
    }

    public bool ContainsKey(K key)
    {
        return this.GetInner(key).ContainsKey(key);
    }

    public ICollection<K> Keys
    {
        get
        {
            var keys = from pk in _inner.Keys
                       from k in _inner[pk].Keys
                       select k;
            return keys.ToList();
        }
    }

    public bool Remove(K key)
    {
        return this.GetInner(key).Remove(key);
    }

    public bool TryGetValue(K key, out V value)
    {
        return this.GetInner(key).TryGetValue(key, out value);
    }

    public ICollection<V> Values
    {
        get
        {
            var values = from pk in _inner.Keys
                         from v in _inner[pk].Values
                         select v;
            return values.ToList();
        }
    }

    public V this[K key]
    {
        get
        {
            return this.GetInner(key)[key];
        }
        set
        {
            this.GetInner(key)[key] = value;
        }
    }

    public void Add(KeyValuePair<K, V> item)
    {
        this.GetInner(item.Key).Add(item.Key, item.Value);
    }

    public void Clear()
    {
        _inner.Clear();
    }

    public bool Contains(KeyValuePair<K, V> item)
    {
        var inner = this.GetInner(item.Key);
        return inner.ContainsKey(item.Key)
            && inner[item.Key].Equals(item.Value);
    }

    public void CopyTo(KeyValuePair<K, V>[] array, int arrayIndex)
    {
        var source = this.ToArray();
        Array.Copy(source, 0, array, arrayIndex, source.Length);
    }

    public int Count
    {
        get
        {
            var counts = from pk in _inner.Keys
                         select _inner[pk].Count;
            return counts.Sum();
        }
    }

    public bool IsReadOnly
    {
        get { return false; }
    }

    public bool Remove(KeyValuePair<K, V> item)
    {
        return this.GetInner(item.Key).Remove(item.Key);
    }

    public IEnumerator<KeyValuePair<K, V>> GetEnumerator()
    {
        return _inner.Keys.SelectMany(pk => _inner[pk]).GetEnumerator();
    }

    System.Collections.IEnumerator
            System.Collections.IEnumerable.GetEnumerator()
    {
        return this.GetEnumerator();
    }
public void Add(K键,V值)
{
this.GetInner(key).Add(key,value);
}
公共bool ContainsKey(K键)
{
返回此.GetInner(键).ContainsKey(键);
}
公共ICollection密钥
{
得到
{
var keys=来自pk in_inner.keys
来自k in_inner[pk]。键
选择k;
返回键。ToList();
}
}
公共布尔删除(K键)
{
返回此.GetInner(键).Remove(键);
}
公共布尔TryGetValue(K键,输出V值)
{
返回此.GetInner(key).TryGetValue(key,out值);
}
公共ICollection值
{
得到
{
var值=来自pk in_inner.Keys
从v到内部[pk]。值
选择v;
返回值。ToList();
}
}
公共V本[K键]
{
得到
{
返回这个.GetInner(key)[key];
}
设置
{
this.GetInner(key)[key]=值;
}
}
公共作废添加(KeyValuePair项)
{
this.GetInner(item.Key).Add(item.Key,item.Value);
}
公共空间清除()
{
_内部。清除();
}
public bool包含(KeyValuePair项)
{
var inner=this.GetInner(item.Key);
返回inner.ContainsKey(item.Key)
&&内部[item.Key].Equals(item.Value);
}
public void CopyTo(KeyValuePair[]数组,int-arrayIndex)
{
var source=this.ToArray();
复制(源,0,数组,arrayIndex,source.Length);
}
公共整数计数
{
得到
{
var计数=来自pk in_inner.Keys
选择_inner[pk].计数;
返回计数。Sum();
}
}
公共图书馆是只读的
{
获取{return false;}
}
公共布尔删除(KeyValuePair项)
{
返回此.GetInner(item.Key).Remove(item.Key);
}
公共IEnumerator GetEnumerator()
{
return _inner.Keys.SelectMany(pk=>_inner[pk]).GetEnumerator();
}
System.Collections.IEnumerator
System.Collections.IEnumerable