Как вы, наверное, догадались, проблема в том, что вы пытаетесь выделить один большой непрерывный блок памяти, который не работает из-за фрагментации памяти. Если бы мне нужно было сделать то, что делаете вы, я бы сделал следующее:
int sizeA = 10000,
sizeB = 10000;
double sizeInMegabytes = (sizeA * sizeB * 8.0) / 1024.0 / 1024.0;
double[][] randomNumbers = new double[sizeA][];
for (int i = 0; i < randomNumbers.Length; i++)
{
randomNumbers[i] = new double[sizeB];
}
Затем, чтобы получить конкретный индекс, который вы должны использовать randomNumbers[i / sizeB][i % sizeB]
.
Другой вариант, если вы всегда обращаетесь к значениям по порядку, может заключаться в использовании перегруженного конструктора для указания начального числа. Таким образом, вы получите полуслучайное число (например, DateTime.Now.Ticks
), сохраните его в переменной, а затем, когда вы начнете просматривать список, вы создадите новый случайный экземпляр, используя исходное семя:
private static int randSeed = (int)DateTime.Now.Ticks;
private static Random GetNewRandomIterator()
{
return new Random(randSeed);
}
Важно отметить, что, хотя блог, связанный с ответом Фредрика Мёрка, указывает, что проблема обычно связана с нехваткой адресного пространства, он не перечисляет ряд других проблем, таких как ограничение размера объекта CLR 2 ГБ (упомянуто в комментарии от ShuggyCoUk в том же блоге), приукрашивает фрагментацию памяти и не упоминает влияние размера файла подкачки (и то, как это можно решить с помощью CreateFileMapping
функции ).
Ограничение 2 ГБ означает, что он randomNumbers
должен быть менее 2 ГБ. Поскольку массивы являются классами и сами по себе имеют некоторые накладные расходы, это означает, что массив double
должен быть меньше 2 ^ 31. Я не уверен, насколько должна быть длина меньше 2 ^ 31, но накладные расходы на массив .NET? обозначает 12-16 байтов.
Фрагментация памяти очень похожа на фрагментацию жесткого диска. У вас может быть 2 ГБ адресного пространства, но по мере создания и уничтожения объектов между значениями будут промежутки. Если эти зазоры слишком малы для вашего большого объекта, и дополнительное пространство не может быть запрошено, тогда вы получитеSystem.OutOfMemoryException
. Например, если вы создаете 2 миллиона объектов по 1024 байта, вы используете 1,9 ГБ. Если вы удалите каждый объект, адрес которого не кратен 3, вы будете использовать 0,6 ГБ памяти, но он будет распределен по адресному пространству с 2024-байтовыми открытыми блоками между ними. Если вам нужно создать объект размером 0,2 ГБ, вы не сможете это сделать, потому что нет блока, достаточно большого для его размещения, и невозможно получить дополнительное пространство (при условии 32-битной среды). Возможные решения этой проблемы - это использование более мелких объектов, уменьшение объема данных, которые вы храните в памяти, или использование алгоритма управления памятью для ограничения / предотвращения фрагментации памяти. Следует отметить, что если вы не разрабатываете большую программу, которая использует большой объем памяти, это не будет проблемой. Также,
Поскольку большинство программ запрашивают рабочую память у ОС и не запрашивают сопоставление файлов, они будут ограничены оперативной памятью системы и размером файла подкачки. Как отмечено в комментарии Нестора Санчеса (Néstor Sánchez) в блоге, с управляемым кодом, таким как C #, вы привязаны к ограничению RAM / файла страницы и адресному пространству операционной системы.
Это было намного дольше, чем ожидалось. Надеюсь, это кому-то поможет. Я разместил его, потому что я столкнулся с System.OutOfMemoryException
запуском программы x64 в системе с 24 ГБ ОЗУ, хотя в моем массиве было всего 2 ГБ.