Почему я получаю исключение из памяти в своем приложении С#?
Моя память 4G физическая, но почему я получил исключение из памяти, даже если я создаю только объект памяти 1.5G. Любые идеи почему? (Я видел в то же время на вкладке производительности диспетчера задач память не занята полностью, и я мог бы также ввести здесь - так что память на самом деле невелика, поэтому я думаю, что я ударил некоторые другие ограничения памяти)?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace TestBigMemoryv1
{
class MemoryHolderFoo
{
static Random seed = new Random();
public Int32 holder1;
public Int32 holder2;
public Int64 holder3;
public MemoryHolderFoo()
{
// prevent from optimized out
holder1 = (Int32)seed.NextDouble();
holder2 = (Int32)seed.NextDouble();
holder3 = (Int64)seed.NextDouble();
}
}
class Program
{
static int MemoryThreshold = 1500; //M
static void Main(string[] args)
{
int persize = 16;
int number = MemoryThreshold * 1000 * 1000/ persize;
MemoryHolderFoo[] pool = new MemoryHolderFoo[number];
for (int i = 0; i < number; i++)
{
pool[i] = new MemoryHolderFoo();
if (i % 10000 == 0)
{
Console.Write(".");
}
}
return;
}
}
}
Ответы
Ответ 1
В обычном 32-битном приложении Windows процесс имеет только 2 ГБ адресной памяти. Это не имеет отношения к количеству доступной физической памяти.
Таким образом, доступно 2 Гб, но 1.5 - это максимум, который вы можете выделить. Ключ в том, что ваш код не является единственным кодом, запущенным в этом процессе. Другой .5 ГБ, вероятно, CLR плюс фрагментация в этом процессе.
Обновление: в .Net 4.5 в 64-битном процессе вы можете иметь большие массивы, если включена опция gcAllowVeryLargeObjects:
На 64-разрядных платформах допускается использование массивов размером более 2 гигабайт (ГБ) в общем размере. Максимальное количество элементов в массиве - UInt32.MaxValue.
<configuration>
<runtime>
<gcAllowVeryLargeObjects enabled="true" />
</runtime>
</configuration>
Ответ 2
Просто добавочно к другим точкам; если вы хотите получить доступ к грязному объему памяти, рассмотрите x64 - но имейте в виду, что максимальный размер одиночного объекта составляет 2 ГБ. И поскольку ссылки больше в x64, это означает, что вы фактически получаете меньший максимальный размер массива/списка для ссылочных типов. Конечно, к тому времени, когда вы нажмете этот предел, вы, вероятно, все испортили!
Другие параметры:
- использовать файлы
- использовать базу данных
(очевидно, что оба имеют разницу в производительности по сравнению с оперативной памятью)
Обновление. В версиях .NET до 4.5 максимальный размер объекта составляет 2 ГБ. Начиная с 4.5 и выше вы можете выделить более крупные объекты, если gcAllowVeryLargeObjects включен. Обратите внимание, что ограничение для string
не влияет, но "массивы" также должны охватывать "списки", поскольку списки поддерживаются массивами.
Ответ 3
Просто добавьте к предыдущим ответам: вы можете выйти за пределы 2Gb для систем, загружаемых с флагами загрузки /3Gb [и опционально userva].
Ответ 4
Убедитесь, что вы создаете 64-битный процесс, а не 32-разрядный, который является стандартным способом компиляции Visual Studio. Для этого щелкните правой кнопкой мыши по вашему проекту, Свойства → Сборка → целевая платформа: x64. Как и любой 32-разрядный процесс, приложения Visual Studio, скомпилированные в 32-битных, имеют ограничение на виртуальную память 2 ГБ.
Каждый процесс имеет свою собственную виртуальную память, называемую адресным пространством, в которое он отображает код, который он выполняет, и данные, которыми он управляет. 32-разрядный процесс использует 32-разрядные указатели адресов виртуальной памяти, что создает абсолютный верхний предел 4 ГБ (2 ^ 32) для объема виртуальной памяти, который может адресовать 32-битный процесс. Однако для работы операционной системы требуется половина (для ссылки на собственный код и данные), создавая ограничение в 2 ГБ для каждого процесса. Если ваше 32-разрядное приложение пытается потреблять больше, чем все 2 ГБ его адресного пространства, оно вернет "System.OutOfMemory", даже если физическая память вашего компьютера не заполнена.
64-битные процессы не имеют этого ограничения, так как используют 64-разрядные указатели, поэтому их теоретическое максимальное адресное пространство составляет 16 экзабайт (2 ^ 64). На самом деле Windows x64 ограничивает виртуальную память процессов до 8 ТБ. Тогда решение проблемы с памятью необходимо скомпилировать в 64-разрядной версии.
Однако размер объектов в Visual Studio по-прежнему ограничен 2 ГБ. Вы сможете создать несколько массивов, размер которых будет больше 2 ГБ, но по умолчанию вы не можете создавать массивы размером более 2 ГБ. Надеюсь, если вы все еще хотите создавать массивы размером более 2 ГБ, вы можете сделать это, добавив следующий код в файл app.config:
<configuration>
<runtime>
<gcAllowVeryLargeObjects enabled="true" />
</runtime>
</configuration>
Ответ 5
У вас есть адресная память с максимальной пропускной способностью 2 ГБ в качестве 32-битного приложения, как упоминалось в других плакатах. Не забывайте о накладных расходах. Вы создаете массив из 93 миллионов объектов - если на один объект приходится 4 байта служебных расходов, что дополнительно 350 Мб памяти.
Ответ 6
Еще одна вещь, о которой нужно знать; некоторые объекты .NET требуют "непрерывной" памяти. т.е. если вы пытаетесь выделить большой массив, системе может понадобиться не только достаточная свободная память в вашем процессе, но также и для всей свободной памяти, которая будет в одном большом фрагменте... и, к сожалению, память процесса фрагментируется со временем, поэтому это может не будут доступны.
Некоторые объекты/типы данных имеют это требование, а некоторые не... Я не могу вспомнить, какие из них выполняются, но я, кажется, помню, что StringBuilder и MemoryStream имеют разные требования.
Ответ 7
В 32-разрядной операционной системе Windows максимальная "пользовательская" память, доступная для одного приложения, составляет 2 ГБ... при условии, что у вас в памяти 4 ГБ памяти.
Неконтролируемое потребление памяти приложения VС++ на сервере Windows
http://blogs.technet.com/markrussinovich/archive/2008/07/21/3092070.aspx
(Смешно, что вы спросили об этом, потому что вчера я попросил почти то же самое...)