OutOfMemoryException при заполнении MemoryStream: выделение 256 МБ на 16 ГБ системе

Я запускаю следующий метод на моем сервере IIS разработки (из VS2010 IDE) на 64-разрядной машине с Windows 7 с 16 ГБ установленной оперативной памяти:

public static MemoryStream copyStreamIntoMemoryStream(Stream stream) { long uiLen = stream.Length; byte[] buff = new byte[0x8000]; int nSz; MemoryStream ms = new MemoryStream(); try { while ((nSz = stream.Read(buff, 0, buff.Length)) != 0) { ms.Write(buff, 0, nSz); } } finally { Debug.WriteLine("Alloc size=" + ms.Length); } return ms; } 

и я получаю System.OutOfMemoryException в этой строке:

 ms.Write(buff, 0, nSz); 

Это выбрано, когда выделено 268435456 байтов:

Alloc size = 268435456

который равен 0x10000000 или 256 МБ. Поэтому мне интересно, есть ли какие-то глобальные настройки, которые мне нужно настроить, чтобы они работали?

Вот скриншот настроек конфигурации для проекта: введите описание изображения здесь

Короткий ответ – сервер dev – это 32-битный процесс.

Длинный ответ за «почему всего 256 МБ?»

Прежде всего, давайте разобраться, как это работает.

MemoryStream имеет внутренний байт [] для хранения всех данных. Он не может предсказать точный размер этого буфера, поэтому он просто инициализирует его с некоторым начальным значением.

Свойства Position и Length не отражают фактический размер буфера – они являются логическими значениями, отражающими количество байтов и легко могут быть меньше фактического размера физического буфера.

Когда этот внутренний буфер не может вместить все данные, он должен быть «изменен», но в реальной жизни это означает создание нового буфера в два раза по сравнению с предыдущим, а затем копирование данных из старого буфера в новый буфер.

Итак, если длина вашего буфера составляет 256 МБ, и вам нужны новые данные для записи, это значит, что .Net нужно найти еще один блок данных 512 МБ – все остальное на месте, поэтому куча должна быть не менее 768 МБ на момент выделения памяти, когда вы получаете OutOfMemory.

Также обратите внимание, что по умолчанию ни один объект, включая массивы, в .Net не может иметь размер более 2 ГБ.

Итак, вот образец, который имитирует происходящее:

  byte[] buf = new byte[32768 - 10]; for (; ; ) { long newSize = (long)buf.Length * 2; Console.WriteLine(newSize); if (newSize > int.MaxValue) { Console.WriteLine("Now we reach the max 2Gb per single object, stopping"); break; } var newbuf = new byte[newSize]; Array.Copy(buf, newbuf, buf.Length); buf = newbuf; } 

Если он построен в x64 / AnyCPU и запускается с консоли – все в порядке.

Если он построен на x86 – он не работает в консоли.

Если вы положите его на страницу «Page_Load», встроенную в x64 и открытую с веб-сервера VS.Net, он терпит неудачу.

Если вы сделаете то же самое с IIS – все в порядке.

Надеюсь это поможет.

Если вы используете сервер разработки VS по умолчанию, вы запускаете код в процессе x86 / 32 бит. Если вы используете полный IIS – скорее всего, в IIS, в частности, AppPool настроен на работу в x86 (32-разрядный режим) и, как результат, имеет очень ограниченное адресное пространство (2 ГБ, если вы не отметили свое приложение как Large Address Aware).

В случае IIS убедитесь, что вы настроили опросы пользователей для запуска x64 (не уверены, что такое значение по умолчанию). Убедитесь, что для вашего кода задано значение «AnyCPU» или «x64».

Для автономных приложений C # – по умолчанию они скомпилированы с x86 или AnyCPU / Prefer x86 – изменят целевую платформу на x64.

Чтобы получить поддержку x64 для IIS, вы можете либо установить полный IIS, либо установить IIS Express 8.0 (7.5, который поставляется с Windows 7, всего 32 бит) из Download IIS 8.0 Express .

Боковые заметки:

  • Если вы только что установили полный IIS, обязательно обновите свое решение, чтобы использовать IIS для хоста сайта.
  • У меня нет машины для проверки необходимости каких-либо дополнительных шагов для поддержки x64 для IIS Express. Проверьте этот вопрос. Невозможно получить бета-версию IIS Express 8 для запуска веб-сайта в виде 64-битного процесса, поскольку это может дать вам некоторые идеи.
  • Вы также можете попытаться создать свою собственную версию сервера разработки x64 на основе предложений здесь: совместима ли с Visual Studio 2010 WebDev WebServer (Cassini) 64-разрядная совместимость?
  • интересное OutOfMemoryException с StringBuilder
  • AngularJS - $ destroy удаляет прослушиватели событий?
  • В чем разница между оператором присваивания и конструктором копирования?
  • Слабые справочные преимущества
  • java.lang.OutOfMemoryError: размер растрового изображения превышает бюджет VM - Android
  • Поиск диапазона адресов сегмента данных
  • Будет ли `char` всегда всегда - всегда иметь 8 бит?
  • Создание утечки памяти с помощью Java
  • Определить размер кучи приложения в Android
  • Есть ли способ получить ссылочный адрес?
  • «Ошибка при отсутствии памяти (Java)» при использовании пакетов R и XLConnect
  • Давайте будем гением компьютера.