OutOfMemoryException при добавлении дополнительных элементов в очень большой HashSet‹Int32›

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

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


person Debasis    schedule 27.12.2011    source источник
comment
Просто из чистого любопытства: для чего вам это нужно?   -  person Mike Nakis    schedule 27.12.2011
comment
@MikeNakis: как упоминалось в посте, нам нужно поддерживать высокопроизводительную уникальную коллекцию целых чисел, чтобы удовлетворить некоторые из наших требований.   -  person Debasis    schedule 27.12.2011
comment
@rfmodulator: это простое Windows-приложение на основе WPF.   -  person Debasis    schedule 27.12.2011


Ответы (4)


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

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

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

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

Чтобы установить конфигурация.

Обновлять:

Приведенная выше конфигурация gcAllowVeryLargeObjects поддерживается только в .Net framework 4.5.

person mehul9595    schedule 27.12.2011
comment
Внезапно я стал намного больше воодушевлен .NET 4.5. Я слишком много раз натыкался на ограничение в 2 ГБ. - person Jim Mischel; 27.12.2011
comment
@MitchWheat: да, я забыл упомянуть. обновление моего ответа. Спасибо - person mehul9595; 27.12.2011
comment
Приведенная выше конфигурация gcAllowVeryLargeObjects поддерживает только .Net framework 4.5. Почему я не прочитал эту строчку....почему.... - person Shin Kazama; 22.07.2015
comment
@ mehul9595 mehul9595 Я попробовал этот параметр gcAllowVeryLargeObjects, и он все еще генерирует ошибки OOM около отметки 2 ГБ. - person A X; 27.09.2020

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

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

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

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

person Jim Mischel    schedule 27.12.2011
comment
Dot net позволяет добавлять только 134 217 728 элементов в список Int32. - person Debasis; 27.12.2011
comment
@Debasis: Если вы работаете в 64-битном режиме, я ожидаю, что List<int> даст вам более 500 миллионов записей. Ваши 134 миллиона элементов занимают более 512 мегабайт памяти, что может быть больше, чем вы можете выделить в 32-разрядной среде выполнения. 134 миллиона довольно близко к самому большому HashSet, который вы можете построить, даже в 64-битном режиме. - person Jim Mischel; 27.12.2011

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

person BrianS    schedule 04.01.2012

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

person SqlRyan    schedule 27.12.2011