Подтвердить что ты не робот

Очень большая коллекция в .Net вызывает исключение из памяти

Я тестирую, как большая коллекция может быть в .Net. Технически любой объект коллекции может увеличиться до размера физической памяти.

Затем я протестировал следующий код в терминале, который имеет 16-гигабайтную память, с сервером Windows 2003 и Visual Studio 2008. Я тестировал как код F #, так и код С# и смотрел на Диспетчер задач во время работы. Я вижу, что после роста памяти 2 ГБ программа разбилась с исключением из памяти. Я установил целевую платформу на x64 на странице свойств.

open System.Collections.Generic

let d = new Dictionary<int, int>()

for i=1 to 1000000000 do
    d.Add(i,i)

Я сделал тот же тест в библиотеке коллекций C5. В результате словарь в C5 может использовать всю память. В коде используется C5:

let d = C5.HashDictionary<int, int> ()
for i=1 to 1000000000 do
    d.Add(i,i)

Кто-нибудь знает, почему?

4b9b3361

Ответ 1

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

Ограничение применяется к каждому отдельному объекту, а не к общему размеру всех объектов, что означает, что его относительно легко обходным путем использовать сложную коллекцию.

Здесь обсуждается и код примера...

Кажется, что очень мало официальных документов, которые относятся к этому пределу. В конце концов, это всего лишь деталь реализации текущей CLR. Единственное упоминание, о котором я знаю, на этой странице:

При запуске 64-битного управляемого приложение на 64-битной Windows операционной системы, вы можете создать объект не более 2 гигабайт (ГБ).

Ответ 2

В версиях .NET до 4.5 максимальный размер объекта составляет 2 ГБ. Начиная с 4.5 и выше вы можете выделить более крупные объекты, если gcAllowVeryLargeObjects включен. Обратите внимание, что ограничение для string не влияет, но "массивы" также должны охватывать "списки", поскольку списки поддерживаются массивами.

Ответ 3

И чтобы быть понятным, словарь использует один массив для добавления пар. Он выращивается (удваивается?) Каждый раз, когда он заполнен. Когда насчитывается 512 миллионов объектов, его размер составляет 2 ГБ (с 32-битным указателем на объект и предполагает идеальное распределение). Добавление еще одного элемента заставит Словарь попытаться удвоить размер массива снова. Boom.

C5 HashDictionary использует линейное хеширование и, вероятно, использует массив ведер, каждый из которых содержит несколько (16?) элементов. Он должен столкнуться с той же проблемой (много) позже.

Ответ 4

"Разрешить большие объекты" поможет только избавиться от исключения OOM.

Когда нужно хранить очень много объектов, проблема, которую вы увидите, - это GC останавливается (паузы). То, что мы сделали, "скрывает" данные от GC, которые превратились в очень практичное решение.

Смотрите это: https://www.infoq.com/articles/Big-Memory-Part-3

Вы можете использовать кеш, который работает как словарь: https://github.com/aumcode/nfx/tree/master/Source/NFX/ApplicationModel/Pile

см. раздел кэширования