Як ви, напевно, зрозуміли, проблема полягає в тому, що ви намагаєтеся виділити один великий суміжний блок пам'яті, який не працює через фрагментацію пам'яті. Якби мені потрібно було робити те, що ти робиш, я б зробив наступне:
int sizeA = 10000,
sizeB = 10000;
double sizeInMegabytes = (sizeA * sizeB * 8.0) / 1024.0 / 1024.0; //762 mb
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; //Must stay the same unless you want to get different random numbers.
private static Random GetNewRandomIterator()
{
return new Random(randSeed);
}
Важливо зазначити, що хоча в блозі, на який посилається Фредрік Мерк, вказується, що проблема, як правило, пов’язана з браком адресного простору, в ній не вказано низку інших проблем, таких як обмеження розміру об’єкта CLR на 2 ГБ (згадане у коментарі від ShuggyCoUk у тому самому блозі), зачіпає фрагментацію пам’яті та не згадує про вплив розміру файлу сторінки (і про те, як з ним можна вирішити за допомогою CreateFileMapping
функції ).
Обмеження 2 ГБ означає, що воно randomNumbers
має бути менше 2 ГБ. Оскільки масиви є класами і мають деякі накладні витрати, це означає, що масив double
повинен бути меншим за 2 ^ 31. Я не впевнений, наскільки меншою, ніж 2 ^ 31, повинна бути довжина, але накладні витрати на масив .NET? вказує 12 - 16 байт.
Фрагментація пам'яті дуже схожа на фрагментацію HDD. Можливо, у вас є 2 ГБ адресного простору, але під час створення та знищення об’єктів між значеннями будуть прогалини. Якщо ці прогалини занадто малі для вашого великого об'єкта, і додатковий простір не можна вимагати, тоді ви отримаєтеSystem.OutOfMemoryException
. Наприклад, якщо ви створюєте 2 мільйони 1024 байтових об’єктів, тоді ви використовуєте 1,9 ГБ. Якщо ви видалите кожен об'єкт, адреса якого не кратна 3, тоді ви будете використовувати .6 ГБ пам'яті, але він буде розподілений по адресному простору з 2024 байтними відкритими блоками між ними. Якщо вам потрібно створити об’єкт розміром .2 ГБ, ви не зможете цього зробити, оскільки немає блоку, достатньо великого, щоб вмістити його, і додатковий простір отримати не вдається (при умові 32-бітового середовища). Можливими рішеннями цієї проблеми є такі речі, як використання менших об'єктів, зменшення обсягу даних, які ви зберігаєте в пам'яті, або використання алгоритму управління пам'яттю для обмеження / запобігання фрагментації пам'яті. Слід зазначити, що якщо ви не розробляєте велику програму, яка використовує великий обсяг пам'яті, це не буде проблемою. Крім того,
Оскільки більшість програм вимагають робочої пам'яті від ОС і не вимагають відображення файлів, вони будуть обмежені оперативною пам’яттю системи та розміром файлу сторінки. Як зазначається в коментарі Нестора Санчеса (Néstor Sánchez) у блозі, з керованим кодом, таким як C #, ви застрягли в обмеженні ОЗУ / файлів сторінок та адресному просторі операційної системи.
Це було набагато довше, ніж очікувалося. Сподіваємось, це комусь допомагає. Я опублікував його, тому що зіткнувся із System.OutOfMemoryException
запущеною програмою x64 в системі з 24 Гб оперативної пам'яті, хоча мій масив містив лише 2 Гб речей.