Почему "Любой процессор (предпочтительный 32-разрядный)" позволяет мне выделять больше памяти, чем x86 в .NET 4.5?

В соответствии со многими ответами SO и это широко цитируемое сообщение в блоге, приложение .NET 4.5, построенное для "Any CPU" с "предпочтительным 32" -бит "будет работать как 32-разрядный процесс как в 32-разрядной, так и в 64-разрядной системах (в отличие от .NET 4.0 и ранее). Другими словами, x86 и AnyCPU с "предпочтительным 32-битным" выбранным эквивалентом (игнорируя, может ли он запускаться на ARM).

Однако мои тесты показали, что в 64-битной системе приложение AnyCPU предпочитает 32-разрядное приложение (которое я уверен, запускает 32-разрядный) может выделить больше памяти, чем x86. Я написал консольное приложение .NET 4.5 С#, которое выделяет массивы в 10 Мбайт байт в цикле (сохраняя ссылки, конечно), пока не попадет в OutOfMemoryException и не запустит его в 64-разрядной системе с большим количеством ОЗУ. Когда он построен как x86, он падает примерно на 1,2 ГБ. Один и тот же код, построенный как "Любой процессор (предпочтительный 32-разрядный)", достигает 1,5 ГБ.

Почему разница?

Ответы

Ответ 1

Оказывается, что в Visual Studio 2015 создание в виде "AnyCPU (предпочтительно 32-битного)" устанавливает бит IMAGE_FILE_LARGE_ADDRESS_AWARE в исполняемом файле (эквивалентно запуску editbin /LARGEADDRESSAWARE на нем), тогда как он не для сборки x86, Это можно подтвердить с помощью dumpbin /HEADERS и поискать строку "Приложение может обрабатывать большие ( > 2 ГБ) адреса".

Это не относится к Visual Studio 2013. Это изменение явно недокументировано.

В теории это должно дать CLR еще 2 ГБ для игры. Я не знаю, почему распределяемая память увеличивается примерно на 300 МБ.

Ответ 2

У меня была такая же проблема, и я хотел оставить x86. Большинство наших приложений зависят от внешних 32-разрядных сборок, и когда разработчики видят любой процессор, они склонны менять его на x86. Я обнаружил, что editbin/largeaddressaware $ (TargetPath) не работает в VS 2017. Поэтому я использовал следующий пакет Nuget и сохранил свой проект на x86.

https://www.nuget.org/packages/LargeAddressAware/ https://github.com/KirillOsenkov/LargeAddressAware

Чтобы использовать, вы добавляете пакет Nuget, а затем помещаете в файл проекта следующее:

<PropertyGroup>
  <LargeAddressAware>true</LargeAddressAware>
</PropertyGroup>

Это сработало в моем случае.