当向一个非常大的hashset中添加更多的项时,OutOfMemoryException
本文关键字:添加 OutOfMemoryException hashset 一个 非常 | 更新日期: 2023-09-27 18:18:47
试图在HashSet<Int32>
中添加23997908th
项时抛出类型为System.OutOfMemoryException
的异常。
我们需要维护Int32
. maxvalue即2147483647
的整数大小的高性能唯一集合。Int32
中的HashSet
只能存储23997907
项。寻找解决这个问题的建议
HashSet(of T)对象的容量是该对象可以容纳的元素数量。对象的容量会随着添加元素而自动增加。
如果您使用64位系统,您可以将Hashset的最大容量增加到20亿通过在运行时环境中将gcAllowVeryLargeObjects的enabled属性设置为true来获取元素。
你可以在配置文件中启用这个设置,
<configuration>
<runtime>
<gcAllowVeryLargeObjects enabled="true" />
</runtime>
</configuration>
检查此MSDN链接是否设置了配置。
更新:以上配置gcAllowVeryLargeObjects仅支持。net framework 4.5。
HashSet
增长一倍。因此,当列表中有23,997,907个元素并尝试添加下一个元素时,它会尝试将其后备数组的大小增加一倍。这种分配导致它超出了可用内存。我假设您在32位系统上运行这个程序,因为在64位系统上,HashSet<object>
可以容纳多达8900万个条目。在32位运行时中,该限制约为6170万项。
你需要做的是预先分配HashSet
来容纳你需要的尽可能多的项目。不幸的是,没有直接的方法可以做到这一点。HashSet
没有一个构造函数可以预先为它分配给定的容量。
List
,用它初始化HashSet
,然后在HashSet
上调用Clear
。这最终会给你一个没有任何道具的HashSet
,但却拥有你所要求的最大容量。我在一篇博客文章中展示了如何做到这一点:更多关于。net集合大小。
对HashSet
大小的限制是由于。net中2g的限制。单个对象的大小不能超过2g。由于分配开销,这个数字实际上略小。
为了解决这个问题,我创建了一个实现HashSet方法和属性(Contains、Add、Count、…)的类,并在幕后保持一个HashSet数组来存储实际数据。第一个实现只是一个接一个地最大化每个HashSet,并在满时移动到数组中的下一个。最新的方法采用哈希键的mod作为内部HashSet数组的索引。这对我来说很好,因为键几乎是随机的,所以值的分布到HashSets数组是相当均匀的。
在这一点上,我认为您需要使用数据库来持久化您的项目(或它们的散列键),因为在默认的。net对象中存储的项目太多了。您也可以编写与HashSet具有相同属性的自定义对象,但这可能比仅使用数据库表来存储哈希要麻烦得多。