我有一些代码,我添加了一个嵌套字典,格式如下
Dictionary<string, Dictionary<string, Dictionary<string, float>>>
这样做后,我注意到我的应用程序的内存使用情况严重上升。这些词典以经常重复的字符串为基础,并且有许多这些字典,大约10万个。
为了解决这个问题,我假设重复的字符串占用了大量的内存。我的解决方案是散列字符串并使用整数(我会保留彩虹表的一个副本,以便我可以在必要时反转哈希)
Dictionary<int, Dictionary<int, Dictionary<int, float>>>
所以我去了一个内存分析器,看看我能得到什么样的尺寸减小。令我震惊的是,我实际上发现字符串存储的大小实际上更小(正常和包容)。
这对我来说并不直观。即使编译器足够智能只存储字符串的一个副本并使用引用,我认为引用将是一个指针,它的大小是int的两倍。我也没有使用任何String.Intern
方法,所以我不知道如何实现这一点(这里也是String.Intern
正确的方法吗?)
我对引擎盖下发生的事情感到非常困惑,任何帮助都会受到赞赏
答案 0 :(得分:6)
如果您的键和值是对象,则字典的每个元素的开销大约为20个字节,每个字典还有几个字节。这是键和值本身消耗的空间的补充。如果你有值类型作为键和值,那么它是12个字节加上键所占用的空间和字典中每个项的值。这是因为元素的数量等于内部字典容量。但通常存在比元素更多的容量,因此浪费了空间。
如果您拥有的元素数量较少的词典,那么浪费的空间通常会是较高的相对百分比。如果我按你的评论说,你的8个元素的词典的容量为11,含2个元素的词的容量为3,而10的元素的容量为11。
如果我理解你的嵌套计数,那么一个顶级字典将代表184个字典元素。但是,如果我们计算未使用的容量,就空间消耗而言,它接近200。每个顶级字典200 * 20 = 4000字节。你有多少人?你说成千上万的物体中有成千上万的它们。每10,000个将消耗大约38 MB的字典开销。添加存储在字典中的对象。
可能的解释是,如果您的密钥没有大量重复引用,那么通过管理哈希代码尝试使其变小的原因就是这样。使用int键替换对象引用键不会更改字典开销量,而是添加新哈希代码集的存储。