Выделение более 1000 МБ памяти в 32-разрядном процессе.NET

Мне интересно, почему я не могу выделить более 1000 МБ памяти в моем 32-разрядном процессе.NET. Следующее мини-приложение генерирует исключение OutOfMemoryException после выделения 1000 МБ. Почему 1000 МБ, а не, скажем, 1,8 ГБ? Можно ли изменить настройки для всего процесса?

static void Main(string[] args)
{
    ArrayList list = new ArrayList();
    int i = 0;
    while (true)
    {
        list.Add(new byte[1024 * 1024 * 10]); // 10 MB
        i += 10;
        Console.WriteLine(i);
    }
}

PS: сбор мусора не помогает.

Изменить, чтобы уточнить, что я хочу: я написал серверное приложение, которое обрабатывает очень большие объемы данных перед записью в базу данных / диск. Вместо того, чтобы создавать временные файлы для всего, я написал кэш в памяти, который делает все это очень быстрым. Но память ограничена, и поэтому я попытался выяснить, каковы ограничения. И удивился, почему моя маленькая тестовая программа вызвала OutOfMemoryException после ровно 1000 МБ.

7 ответов

Решение

Предел виртуального адресного пространства процесса Win32 составляет 1,5 ГБ (не совсем так). Кроме того, в платформах.NET существует ограничение на% памяти, которую может использовать процесс.NET. В machine.config есть элемент processModel с атрибутом memoryLimit, который представляет собой% доступной памяти, которую может использовать процесс. Значение по умолчанию составляет 60%.

Если машина, на которой вы работаете, имеет 2 ГБ памяти или вы не включили ключ /3 ГБ в вашем BOOT.INI, то вы получите ~1,3 ГБ памяти на процесс.

Я не могу найти статью в КБ, но если я правильно помню,.NET 1.x не может обращаться за пределами 1,5 ГБ (1,8 ГБ?) Независимо от ваших настроек.

http://blogs.msdn.com/tmarq/archive/2007/06/25/some-history-on-the-asp-net-cache-memory-limits.aspx http://social.msdn.microsoft.com/Forums/en-US/clr/thread/c50ea343-b41b-467d-a457-c5a735e4dfff http://www.guidanceshare.com/wiki/ASP.NET_1.1_Performance_Guidelines_-_Caching

Наличие огромных блоков памяти никогда не является хорошей идеей, даже в 64-битной. Вы получаете большие проблемы с непрерывной памятью и фрагментацией.

Проблема здесь - найти непрерывный блок. Вы можете попробовать включить режим 3 ГБ (что может помочь найти еще несколько байтов), но я действительно советую против этого. Ответы здесь:

  • использовать меньше памяти
  • использовать базу данных / файловую систему
  • использовать х64

Возможно, вы также захотите прочитать блог Эрика Липперта (у него, кажется, есть запись в блоге для каждого общего вопроса.NET...)

Недавно я занимался широким профилированием ограничений памяти в.NET для 32-битного процесса. Нас всех закидывает мысль о том, что мы можем выделить до 2,4 ГБ (2^31) в приложении.NET, но, к сожалению, это не так:(. Процесс приложения имеет так много места для использования, а операционная система работает отлично Тем не менее, для нашей работы, связанной с управлением ею, сама.NET, похоже, имеет свои собственные издержки, которые составляют примерно 600–800 МБ для типичных реальных приложений, которые увеличивают ограничение памяти. Это означает, что как только вы выделяете массив целых чисел, который занимает около 1.4 ГБ, вы должны ожидать появления исключения OutOfMemoryException().

Очевидно, что в 64-битной версии это ограничение наступает гораздо позже (давайте поговорим через 5 лет:)), но общий размер всего в памяти также увеличивается (я нахожу, что это ~1,7-2 раза) из-за увеличенного размера слова.

Что я точно знаю, так это то, что идея виртуальной памяти из операционной системы определенно НЕ дает вам практически бесконечное пространство для выделения в одном процессе. Это только для того, чтобы все 2,4 ГБ могли быть адресованы всем (многим) приложениям, работающим одновременно.

Я надеюсь, что это понимание несколько помогает.

Первоначально я ответил на что-то связанное здесь (я все еще новичок, поэтому не уверен, как я должен делать эти ссылки):

Есть ли ограничение памяти для одного процесса.NET

Вы можете выделить НАМНОГО БОЛЬШЕ памяти, чем ~2 ГБ, создав приложение для 64-разрядной архитектуры, для чего необходимо создать новую конфигурацию сборки в Visual Studio, а сборка приложения будет выполняться только в 64-разрядных версиях Windows., В.NET, используя опцию по умолчанию "Любой ЦП" для вашего приложения, я нахожу, что могу выделить только 1,5 ГБ памяти из кучи (даже на 64-разрядной машине с Windows), потому что приложение на самом деле работает только в 32-битном режиме, когда он встроен в режим "Любой процессор". Но, компилируя архитектуру x64, вы можете выделить гораздо больше памяти из кучи во время выполнения вашего приложения, и я объясню, как создать сборку x64 для вашего приложения ниже:

Опять же, используя обычную (по умолчанию) опцию сборки "Любой ЦП" в вашем проекте.NET, ваше приложение ВСЕГДА будет работать в 32-битном режиме, даже в 64-битной ОС Windows. Поэтому вы не сможете выделить более 1,5-2 ГБ оперативной памяти во время выполнения приложения. Чтобы запустить приложение.NET в истинном 64-разрядном режиме, вам нужно будет зайти в диспетчер конфигурации сборки и создать тип сборки для архитектуры x64, а затем перекомпилировать свою программу для x64 явно, используя этот тип сборки. Параметр режима сборки x64 можно создать для вашего решения.NET, выполнив следующие действия:

  1. На панели "Обозреватель решений" Visual Studio щелкните правой кнопкой мыши значок "Решение" и выберите "Configuration Manager" во всплывающем меню. Откроется диалоговое окно "Диспетчер конфигурации" для файла.NET Solution.
  2. Справа, в верхней части диалогового окна "Диспетчер конфигурации", нажмите стрелку вниз и выберите параметр "<новый>". Откроется диалоговое окно "Новая платформа решений".
  3. В диалоговом окне "Новая платформа решений" для параметра "Платформа" выберите "x64" в раскрывающемся меню. Затем нажмите кнопку "ОК", и новая опция сборки x64 теперь будет доступна в диалоговом окне Configuration Manager.
  4. Затем в диалоговом окне "Диспетчер конфигурации" выберите "x64" в раскрывающемся меню "Active Solution Platform". Нажмите кнопку "Закрыть".
  5. В панели "Обозреватель решений" Visual Studio щелкните правой кнопкой мыши значок CS Project и выберите параметр "Свойства" во всплывающем меню (последний параметр в нижней части этого меню). Откроется окно свойств проекта CS.
  6. В левой части окна свойств CS Project нажмите на вкладку "Build", чтобы отобразить свойства сборки для вашего проекта кода. В верхней части этого окна обратите внимание, что "Платформа" должна теперь сказать "x64" (в отличие от опции "Любой процессор" по умолчанию). Если в раскрывающемся списке "Платформа" не отображается "x64", выберите его сейчас.
  7. Затем просто соберите свой код и в папке "bin" теперь у вас должна быть папка x64 с новой 64-битной сборкой вашего приложения.

Использование 64-битной сборки вашего приложения в 64-битной ОС Windows позволит вашей программе выделять гораздо больше, чем ~2 ГБ памяти, предположительно до 2^64 адресных пространств (если у вас есть ОЗУ и дисковое пространство, которое являются реальными ограничивающими факторами на момент написания этого ответа).

Если у вас все еще не хватает памяти в приложении, вы также можете увеличить размер файла подкачки памяти Windows. В Windows файл подкачки позволяет операционной системе перемещать память из ОЗУ на диск, если ему не хватает места в ОЗУ. Но перемещение разделов оперативной памяти на диск и с него сопряжено с большими временными затратами, поэтому это может серьезно повлиять на производительность вашего приложения. Независимо от производительности, увеличив размер страницы, вы можете (теоретически) сделать файл подкачки настолько большим, насколько доступно свободное место на диске C: вашего компьютера с Windows. В этом случае ваше приложение сможет выделить, например, до 4 ТБ памяти (или любой другой объем памяти, на который установлен размер файла подкачки) во время выполнения вашей программы. Чтобы изменить параметры файла подкачки для вашего компьютера с Windows, сделайте следующее:

  1. Откройте диалоговое окно "Свойства системы", щелкнув правой кнопкой мыши "Этот компьютер" и выбрав "Свойства" во всплывающем меню. Это также можно выполнить в более поздних версиях Windows (Windows 10, Win 2012 Server и т. Д.), Перейдя в "Пуск" > "Панель управления" > "Система и безопасность" > "Система".
  2. В левой части диалогового окна "Система" выберите параметр "Дополнительные свойства системы". Появится вкладка "Дополнительно" устаревшего диалога "Свойства системы" для Windows.
  3. На вкладке "Дополнительно" диалогового окна "Свойства системы" нажмите кнопку "Настройки" в поле "Производительность". Откроется диалоговое окно "Параметры производительности".
  4. В диалоговом окне "Параметры производительности" перейдите на вкладку "Дополнительно", чтобы увидеть текущие настройки размера файла страницы памяти Windows.
  5. Чтобы увеличить размер файла подкачки, нажмите кнопку "Изменить", и откроется диалоговое окно "Виртуальная память".
  6. В диалоговом окне "Виртуальная память" выберите диск "C:", затем в разделе "Нестандартный размер" установите размеры "Начальный" и "Максимальный". Вы можете использовать любой размер вплоть до максимального объема свободного места на диске C:, но внесение этого изменения зарезервирует это пространство для файла подкачки на жестком диске.
  7. Затем нажмите "ОК" во всех диалоговых окнах, чтобы зафиксировать новые настройки. Затем перезагрузите компьютер, чтобы убедиться, что все изменения были выполнены правильно и что новые параметры файла подкачки работают.

В любом случае, я надеюсь, что это поможет людям понять, почему они могут столкнуться с проблемой ограничения памяти размером 1,5–2 ГБ в приложении.NET даже при работе на 64-разрядной машине с Windows. Это может быть очень запутанным вопросом для людей, и я надеюсь, что мое объяснение имеет смысл. Пожалуйста, не стесняйтесь присылать мне вопросы об этом ответе, если это необходимо.

Скомпилировать программу как Any CPU и у вас будет неограниченный объем памяти для использования, и программа все еще может использовать импорт DLL x86 (32-бит) !!!

Я думаю, что проблема заключается в том, что это приложение будет добавлять 10 МБ при каждом цикле, который он делает, и цикл: "while(true)", что означает, что он будет добавлять эти 10 МБ до тех пор, пока приложение не будет остановлено. Так что, если бы он работал на 100 циклах, это добавило бы к ОЗУ около 1 ГБ, и я предполагаю, что это сделало бы это менее чем за 30 секунд. Я хочу сказать, что вы пытаетесь использовать 10 мегабайт памяти на цикл, в бесконечном цикле

Мне очень жаль, если я не понял вашу точку зрения, но:

static void Main(string[] args)
{
    ArrayList list = new ArrayList();
    int i = 0;
    while (true)
    {
        using(byte newBt = new byte[1024 * 1024 * 10])
        {
            list.Add(newBt); // 10 MB
            i += 10;
            Console.WriteLine(i);
        }
    }
}

Вы пробовали использовать метод? И это может быть глупым вопросом, но почему вы создали вечную петлю? O, если вы попробуете код, удалите символы>.> XD.

Источник: http://msdn.microsoft.com/en-us/library/yh598w02(v=vs.80).aspx

Другие вопросы по тегам