Почему я получаю исключение нехватки памяти в моем приложении C#?
У меня физическая память 4G, но почему я получил исключение из памяти, даже если я создаю объект памяти размером всего 1,5 ГБ. Есть идеи, почему? (В то же время я видел, что на вкладке производительности диспетчера задач память не полностью занята, и я также мог ввести здесь - так что памяти на самом деле не мало, поэтому я думаю, что я столкнулся с некоторыми другими ограничениями памяти)?
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;
}
}
}
Ответов (7)7
В обычном 32-битном приложении Windows процесс имеет только 2 ГБ адресуемой памяти. Это не имеет отношения к доступному объему физической памяти.
Итак, доступно 2 ГБ, но 1,5 - это максимум, который вы можете выделить. Ключ в том, что ваш код - не единственный код, выполняющийся в процессе. Другой 0,5 ГБ - это, вероятно, среда CLR плюс фрагментация в процессе.
Обновление: в .Net 4.5 в 64-битном процессе вы можете иметь большие массивы, если включен параметр gcAllowVeryLargeObjects :
На 64-битных платформах включает массивы, общий размер которых превышает 2 гигабайта (ГБ). Максимальное количество элементов в массиве - UInt32.MaxValue.
<configuration>
<runtime>
<gcAllowVeryLargeObjects enabled="true" />
</runtime>
</configuration>
Убедитесь, что вы создаете 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>
В 32-разрядной операционной системе Windows максимальная память «пользовательского режима», к которой может получить доступ одно приложение, составляет 2 ГБ ... при условии, что у вас есть 4 ГБ памяти на коробке.
Потребление памяти неуправляемым приложением VC++ на сервере Windows
http://blogs.technet.com/markrussinovich/archive/2008/07/21/3092070.aspx
(Забавно, что вы спросили об этом, потому что вчера я спросил почти то же самое ...)
Просто в дополнение к другим пунктам; если вам нужен доступ к грязному объему памяти, рассмотрите вариант x64, но имейте в виду, что максимальный размер одного объекта по-прежнему составляет 2 ГБ. И поскольку ссылки больше в x64, это означает, что вы фактически получаете меньший максимальный размер массива / списка для ссылочных типов. Конечно, к тому времени, когда вы достигнете этого предела, вы, вероятно, все равно будете делать что-то не так!
Другие варианты:
- использовать файлы
- использовать базу данных
(очевидно, что оба имеют разницу в производительности по сравнению с внутренней памятью)
Обновление: в версиях .NET до 4.5 максимальный размер объекта составляет 2 ГБ. Начиная с версии 4.5 вы можете выделять более крупные объекты, если включен gcAllowVeryLargeObjects . Обратите внимание, что ограничение для string
не изменяется, но «массивы» должны охватывать и «списки», поскольку списки поддерживаются массивами.
Еще одна вещь, о которой нужно знать; некоторые объекты .NET требуют «непрерывной» памяти. то есть, если вы пытаетесь выделить большой массив, системе может потребоваться не только достаточно свободной памяти в вашем процессе, но и для того, чтобы вся эта свободная память находилась в одном большом фрагменте ... и, к сожалению, память процесса со временем фрагментируется, поэтому это может не будет в наличии.
Некоторые объекты / типы данных имеют это требование, а некоторые нет ... Я не могу вспомнить, какие именно, но я, кажется, помню, что у StringBuilder и MemoryStream разные требования.