将更多项添加到非常大的HashSet 时出现OutOfMemoryException

尝试在HashSet添加23997908th项时抛出类型System.OutOfMemoryException类型的exception。

我们需要维护一个高性能的整数sizeof Int32 .MaxValue集合,即2147483647Int32 HashSet只能存储23997907项目。 寻找解决此问题的建议。

HashSet(Of T)对象的容量是对象可以容纳的元素数。 随着元素的添加,对象的容量会自动增加。

如果您使用的是64位系统,则可以通过在运行时环境中将gcAllowVeryLargeObjects的enabled属性设置为true来将Hashset的最大容量增加到20亿个元素。

您可以从配置文件启用此设置,

      

检查此MSDN链接以设置配置。

更新:

上面的配置gcAllowVeryLargeObjects仅支持.Net framework 4.5。

HashSet增长倍增。 因此,当列表中有23,997,907个项目并尝试添加下一个项目时,它会尝试将其后备arrays的大小加倍。 而这种分配导致它超过可用内存。 我假设你在32位系统上运行它,因为在64位系统上, HashSet可以容纳超过8900万个项目。 在32位运行时中,限制大约为6170万个项目。

您需要做的是预先分配HashSet以根据需要保存HashSet项目。 不幸的是,没有直接的方法可以做到这一点。 HashSet没有一个构造函数,它将使用给定的容量预先分配它。

但是,您可以创建一个List ,使用它来初始化HashSet ,然后在HashSet上调用Clear 。 最终会给你一个没有项目的HashSet ,但是你要求的最大容量。 我在博客文章中展示了如何做到这一点: 有关.NET Collection Sizes的更多信息 。

HashSet大小的限制是由于.NET中的两千兆字节限制。 没有单个对象可以大于2千兆字节。 由于分配开销,该数字实际上略小。

为了解决这个问题,我创建了一个实现HashSet方法和属性(Contains,Add,Count,…)的类,并在后台保存一组HashSets来存储实际数据。 第一个实现只是逐个最大化每个HashSet,并在满时移动到数组中的下一个。 最新版本将一个mod的哈希键作为内部HashSet数组的索引。 这对我很有用,因为键几乎是随机的,因此值到HashSets数组的分布非常均匀。

此时,我认为您需要使用数据库来保存您的项目(或其哈希键),因为这是太多要存储在默认.NET对象中的项目。 您还可以编写一个与HashSet具有相同属性的自定义对象,但仅使用数据库表来存储哈希值可能会更麻烦。