2016-10-31 7 views
2

Каковы ограничения памяти для Hashset<string> в C#?Каковы ограничения памяти для HashSet?

Я видел, что .NET имеет ограничение памяти 2 Гбит на объект? Является ли эта информация еще точным? Используется ли это для Hashsets?

В настоящее время я работаю над приложением, которое работает с большим hashset, и я видел, что как только я создаю dll для 64-битной среды, я получаю OutOfMemory только тогда, когда мой 8-гигабайтный оперативный компьютер достигает пределов памяти.

Если бы у меня было 16 ГБ ОЗУ, объект увеличивался бы до тех пор, пока он не достигнет ограничений аппаратного обеспечения?

+0

Duplicate? Http: // StackOverflow.com/a/1088044/993547 –

+1

Ограничение 2GB для отдельных объектов и в качестве примера будет влиять на максимальный размер массивов. Однако, если 'T', которые вы сохранили в hashset, являются классами, тогда в хешсет сохраняется только 32- или 64-разрядная ссылка, фактический экземпляр объекта и его размер не будут иметь значения в контексте HashSet. OutOfMemory в целом означает, что в .NET действительно закончилась нехватка памяти, это никогда не должно означать, что какой-то произвольный объект решил, что это настолько высоко, насколько это возможно. –

+0

Ограничение на 2 ГБ не так просто; существует опция 'gcAllowVeryLargeObjects', но предел' int.MaxValue' по-прежнему применяется, даже если это включено; в случае 'T' =' string', вы можете получить немного больше, хотя - ** если ** 'HashSet ' ограничен большими массивами! не является тривиальным –

ответ

2

Существует ограничение на 2 ГБ на объект, но помните, что ссылочный тип использует только размер указателя (8 байтов для x64), когда это поле в классе.

размеров матрицы памяти вычисляются следующим образом (без учета фиксированных накладных расходов):

Для массивов типов структуры: размер памяти

  • Array = #elements в массиве * размер каждого элемента

Для массивов ссылочных типов:

  • массива памяти size = # elementments в массиве * размер ссылки (4 байта для x8x, 8 байтов для x64)

Так что HashSet может ссылаться на объекты на сумму намного больше, чем ограничение 2 ГБ. Просто добавьте размер каждого поля в классе - 64 бита для ссылочных типов и полный размер для типов struct - он должен быть меньше 2 ГБ.

Например, у вас может быть класс, содержащий 16x1GB массивы байтов.

Также обратите внимание, что можно настроить приложение, чтобы разрешить массивы размером более 2 ГБ, хотя максимальное количество элементов в одномерном массиве по-прежнему не может превышать 2G (2 * 1024 * 1024 * 1024).

Я подозреваю, что объекты, которые вы храните в HashSet, являются ссылочными типами, поэтому для каждого из них во внутреннем массиве HashSet используется только 64 бита, а полный размер каждого из них намного больше, чем 64 бит - который дает общий размер, превышающий 2 ГБ.

Глядя на referencesource для HashSet показывает, что используются следующие массивы:

private int[] m_buckets; 
private Slot[] m_slots; 

Где Slot определяется следующим образом:

internal struct Slot { 
    internal int hashCode;  // Lower 31 bits of hash code, -1 if unused 
    internal T value; 
    internal int next;   // Index of next entry, -1 if last 
} 

Похоже, каждый Slot структуры занимает 16 байт на 64 когда T является ссылочным типом, что означает, что HashSet будет вызывать OutOfMemory, когда количество используемых слотов превышает 2GB/16 = 128M элементов

(Если T - это структура, то в зависимости от его размера у вас скоро будет нехватка памяти.)

+0

@LaRage. Поскольку вы храните строки, вы сможете хранить ~ 128 * 1024 * 1024 из них перед тем, как получить OutOfMemory. Если вы включите большой объект, я * думаю * вы могли бы хранить ~ 2 * 1024 * 1024 * 1024 из них, прежде чем получать исключение из-за наличия слишком большого количества элементов. Но вам нужно будет проверить это, чтобы быть определенным!Я точно не знаю. –