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

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

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

open System.Collections.Generic let d = new Dictionary() for i=1 to 1000000000 do d.Add(i,i) 

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

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

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

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

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

Здесь есть обсуждение и примерный код …

  • BigArray , преодолевая ограничение размера массива 2 ГБ

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

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

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

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

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

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

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

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

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

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

Давайте будем гением компьютера.