OutOfMemoryException при добавлении большего количества элементов в очень большой набор HashSet <Int32>

Исключение типа System.OutOfMemoryException было выбрано при попытке добавить элемент 23997908th в HashSet<Int32>.

Нам нужно поддерживать уникальную коллекцию с высокой производительностью целого размера Int32.MaxValue i.e. 2147483647. HashSet of Int32 может хранить только 23997907 элементы в нем. Ищете предложение решить эту проблему.

Ответ 1

емкость объекта HashSet (Of T) - это количество элементов, которые может удерживать объект. емкость объекта автоматически увеличивается по мере добавления элементов к нему.

если вы используете 64-битную систему, вы можете увеличить максимальную емкость Hashset до 2 миллиардов элементов, установив атрибут enabled gcAllowVeryLargeObjects в true в среде выполнения.

Вы можете включить эти настройки из файла конфигурации,

<configuration>
 <runtime>
   <gcAllowVeryLargeObjects enabled="true" />
  </runtime>
 </configuration>

Отметьте эту ссылку MSDN для настройки конфигурации.

Обновление:

Выше config gcAllowVeryLargeObjects поддерживается только для .NET Framework 4.5.

Ответ 2

HashSet растет удвоением. Поэтому, когда у вас есть 23,997,907 пунктов в списке и попробуйте добавить следующий, он пытается удвоить размер своего массива. И это распределение заставляет его превышать доступную память. Я предполагаю, что вы запускаете это в 32-битной системе, потому что в 64-битной системе HashSet<object> может содержать более 89 миллионов элементов. Предел составляет около 61,7 миллиона элементов в 32-разрядной среде выполнения.

Что вам нужно сделать, это предварительно выделить HashSet для хранения как можно большего количества элементов. К сожалению, нет прямого способа сделать это. HashSet не имеет конструктора, который предварительно распределяет его с заданной емкостью.

Однако вы можете создать List, использовать его для инициализации HashSet, а затем вызвать Clear на HashSet. В результате вы получаете HashSet, в котором нет элементов, но вместимость макс, которую вы запросили. Я показал, как это сделать в сообщении в блоге: Подробнее о размерах коллекции .NET.

Ограничения на размер HashSet обусловлены лимитом двух гигабайт в .NET. Ни один объект не может быть больше двух гигабайт. Число на самом деле немного меньше, из-за затрат на распределение.

Ответ 3

Чтобы обойти эту проблему, я создал класс, который реализует методы и свойства HashSet (Contains, Add, Count,...), а за кулисами хранит массив HashSets для хранения фактических данных. Первая реализация просто увеличивала каждый HashSet один за другим и переходила к следующей в массиве, когда была заполнена. Последний принимает мотив хеш-ключа как индекс для внутреннего массива HashSet. Это хорошо работает для меня, так как ключи в значительной степени случайны, поэтому распределение значений в массиве HashSets довольно даже.

Ответ 4

В этот момент, я думаю, вам нужно будет использовать базу данных для сохранения ваших элементов (или их хеш-ключей), поскольку это слишком много элементов для хранения в объектах .NET по умолчанию. Вы также можете написать пользовательский объект, обладающий теми же свойствами, что и HashSet, но это может быть больше проблем с использованием таблицы базы данных для хранения хэшей.