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, но это может быть больше проблем с использованием таблицы базы данных для хранения хэшей.