Подтвердить что ты не робот

Почему я получаю исключение из памяти в своем приложении С#?

Моя память 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;
        }
    }
}
4b9b3361

Ответ 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

(Смешно, что вы спросили об этом, потому что вчера я попросил почти то же самое...)