.net 初始容量字典
我了解到,如果可以估计字典的大小,那么使用初始容量初始化字典可能会带来更好的性能.net 初始容量字典,.net,vb.net,.net,Vb.net,我了解到,如果可以估计字典的大小,那么使用初始容量初始化字典可能会带来更好的性能 Dim MyDataTable As New DataTable 'Fill MyDataTable from Database Dim CapacityEstimate As integer = MyDataTable.Rows.Count Dim MyDictionary As New Dictionary(Of String, MyObjectType)(CapacityEstimate) 'Fill
Dim MyDataTable As New DataTable
'Fill MyDataTable from Database
Dim CapacityEstimate As integer = MyDataTable.Rows.Count
Dim MyDictionary As New Dictionary(Of String, MyObjectType)(CapacityEstimate)
'Fill the Dictionary independent of data table
CapacityEstimate变量只是字典应该保存的键/值对数量的估计(通常在2500到7000之间)。因此,如果我估计它是4000个,最终有4010个对象(我可能会超过或低于,不确定),那么字典会使用大量内存来调整大小,因为其中已经有很多键/值对。这是一个好的解决方案,还是我最好不要用初始容量初始化它。谢谢
编辑:相关但不相同-
如果字典中已经有那么多的键/值对,它会使用大量内存来调整大小吗
只有超出估计容量时,字典才会“调整大小”
Dim MyDataTable As New DataTable
'Fill MyDataTable from Database
Dim CapacityEstimate As integer = MyDataTable.Rows.Count
Dim MyDictionary As New Dictionary(Of String, MyObjectType)(CapacityEstimate)
'Fill the Dictionary independent of data table
将为您估计的项目数保留内存-这将在字典的构造函数中发生
现在,容量和实际大小之间存在差异。容量是指字典在不调整内部存储大小的情况下可以容纳多少项。大小是实际存储在字典中的项目数(即添加到字典中的项目)
如果字典中已经有那么多的键/值对,它会使用大量内存来调整大小吗
只有超出估计容量时,字典才会“调整大小”
Dim MyDataTable As New DataTable
'Fill MyDataTable from Database
Dim CapacityEstimate As integer = MyDataTable.Rows.Count
Dim MyDictionary As New Dictionary(Of String, MyObjectType)(CapacityEstimate)
'Fill the Dictionary independent of data table
将为您估计的项目数保留内存-这将在字典的构造函数中发生
现在,容量和实际大小之间存在差异。容量是指字典在不调整内部存储大小的情况下可以容纳多少项。大小是实际存储在字典中的项目数(即添加到字典中的项目)。这是个好问题。我没有到处找,但奥德的回答对我来说很好
但是,让我们在其上运行一个概念性的微观基准测试:
Dictionary<string, int> FixedCapacity = new Dictionary<string, int>(4000);
Dictionary<string, int> NotFixedCapacity = new Dictionary<string, int>();
Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
for (int i = 0; i < 5000; i++)
{
FixedCapacity.Add(i.ToString(), i);
}
stopWatch.Stop();
Console.WriteLine(string.Format("Fixed initial capacity: {0} ms", stopWatch.ElapsedMilliseconds));
stopWatch.Reset();
stopWatch.Start();
for (int i = 0; i < 5000; i++)
{
NotFixedCapacity.Add(i.ToString(), i);
}
stopWatch.Stop();
Console.WriteLine(string.Format("Not Fixed initial capacity: {0} ms", stopWatch.ElapsedMilliseconds));
Console.ReadLine();
这是另一个好答案,IMO=)
免责声明:不,这不是一个完整的基准测试过程,我只是在一台机器上测量框架的“默认”行为。我已经手动运行了好几次,得到了相同的结果,即使它不在循环中。如果您有更好的基准测试工具,请测试它并将结果粘贴到此处。这是一个好问题。我没有到处找,但奥德的回答对我来说很好
但是,让我们在其上运行一个概念性的微观基准测试:
Dictionary<string, int> FixedCapacity = new Dictionary<string, int>(4000);
Dictionary<string, int> NotFixedCapacity = new Dictionary<string, int>();
Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
for (int i = 0; i < 5000; i++)
{
FixedCapacity.Add(i.ToString(), i);
}
stopWatch.Stop();
Console.WriteLine(string.Format("Fixed initial capacity: {0} ms", stopWatch.ElapsedMilliseconds));
stopWatch.Reset();
stopWatch.Start();
for (int i = 0; i < 5000; i++)
{
NotFixedCapacity.Add(i.ToString(), i);
}
stopWatch.Stop();
Console.WriteLine(string.Format("Not Fixed initial capacity: {0} ms", stopWatch.ElapsedMilliseconds));
Console.ReadLine();
这是另一个好答案,IMO=)
免责声明:不,这不是一个完整的基准测试过程,我只是在一台机器上测量框架的“默认”行为。我已经手动运行了好几次,得到了相同的结果,即使它不在循环中。如果您有更好的基准测试工具,请测试它并将结果粘贴到此处。不要担心小问题。像这样的字典不会占用很多内存,所以让它自己调整大小也不会占用很多内存。真正的存储是键和数据的对象,字典只包含对它们的引用。32位模式下每个条目8字节,因此只有4000 x 8+一些开销=32 KB
此外,您传递的容量用于计算字典中哈希桶的数量。它始终是一个素数,等于或大于指定的容量。质数从该数组中选取(从参考源复制):
如果你超过4000,那么你将得到4049个桶,下一个最大的素数。所以超过4010不会有什么不同。如果它确实需要调整大小,那么它的容量将加倍。因此,一次调整大小将产生8419个桶,远远超过您的最大估计值。调整大小也不是很昂贵,只需几微秒。这就是为什么安德烈看不出有什么不同
这是正确的方法,而不是推理。量。任何人都可以测量。不要担心小东西。像这样的字典不会占用很多内存,所以让它自己调整大小也不会占用很多内存。真正的存储是键和数据的对象,字典只包含对它们的引用。32位模式下每个条目8字节,因此只有4000 x 8+一些开销=32 KB
此外,您传递的容量用于计算字典中哈希桶的数量。它始终是一个素数,等于或大于指定的容量。质数从该数组中选取(从参考源复制):
如果你超过4000,那么你将得到4049个桶,下一个最大的素数。所以超过4010不会有什么不同。如果它确实需要调整大小,那么它的容量将加倍。因此,一次调整大小将产生8419个桶,远远超过您的最大估计值。调整大小也不是很昂贵,只需几微秒。这就是为什么安德烈看不出有什么不同
这是正确的方法,而不是推理。量。任何人都可以测量。我知道这可能太晚了,但无论如何,这可能对任何阅读本文的人都有价值。最好将容量设置为某个已知值的原因是为了防止重新分配。在一个高度繁忙、全天候的服务/应用程序中,内存利用率非常高/极端,您可能希望通过将容量设置为已知大小或某个平均/估计大小来防止内存重新分配,从而避免增加额外的压力
在这种情况下,内存重新分配会在内存空间中产生“(小)洞”,从而导致内存碎片。有一段时间,即使内存仍然很大,因为碎片太多,那么你的应用程序可能会遇到“内存不足”的情况
在.NET4.5.1之前,这一观察结果是正确的,我相信这是我最后一次测试/观察这一点的时候。如果较新的框架版本具有更好的垃圾收集器