当向一个非常大的hashset中添加更多的项时,OutOfMemoryException

本文关键字:添加 OutOfMemoryException hashset 一个 非常 | 更新日期: 2023-09-27 18:18:47

试图在HashSet<Int32>中添加23997908th项时抛出类型为System.OutOfMemoryException的异常。

我们需要维护Int32 . maxvalue即2147483647的整数大小的高性能唯一集合。Int32中的HashSet只能存储23997907项。寻找解决这个问题的建议

当向一个非常大的hashset中添加更多的项时,OutOfMemoryException

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具有相同属性的自定义对象,但这可能比仅使用数据库表来存储哈希要麻烦得多。