Недостатки использования /LARGEADDRESSAWARE для 32-битных исполняемых файлов Windows?
-
21-09-2019 - |
Вопрос
Нам нужно связать один из наших исполняемых файлов с этим флагом, поскольку он использует много памяти.
Но зачем уделять одному EXE-файлу особое внимание?Почему бы не стандартизировать /LARGEADDRESSAWARE?
Итак, вопрос:Есть ли что-то неправильное в использовании /LARGEADDRESSAWARE, даже если оно вам не нужно?Почему бы не использовать его как стандарт для всех EXE-файлов?
Решение
слепо применяя LargeAddressAware
флаг в ваш 32-битный исполняемый файл развертывает бомба замедленного действия!
установив этот флаг ты свидетельствуют об ОС:
да, мое приложение (и все библиотеки DLL, загружаемые во время выполнения) могут работать с адресами памяти до 4 ГБ.
поэтому не ограничивайте VAS для этого процесса 2 ГБ, а разблокируйте полный диапазон (4 ГБ)».
но можете ли вы действительно гарантировать?
Берете ли вы на себя ответственность за все системные библиотеки DLL, распространяемые файлы Microsoft и сторонние модули, которые может использовать ваш процесс?
обычно распределение памяти возвращает виртуальные адреса в порядке от младшего к старшему.поэтому, если ваш процесс не потребляет много памяти (или не имеет очень фрагментированного виртуального адресного пространства), он никогда не будет использовать адреса, выходящие за пределы 2 ГБ.это скрывает ошибки, связанные с высокими адресами.
если такие ошибки существуют, их трудно идентифицировать.они будут время от времени появляться «рано или поздно».это вопрос времени.
к счастью, в ОС Windows есть чрезвычайно удобный общесистемный переключатель:
в целях тестирования используйте параметр реестра MEM_TOP_DOWN.
это заставляет все распределение памяти идти сверху вниз, а не обычно снизу вверх.
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Memory Management]
"AllocationPreference"=dword:00100000
(это шестнадцатеричный код 0x100000.требует перезагрузки Windows, конечно)
если этот переключатель включен, вы сможете выявить проблемы «раньше», а не «позже».в идеале вы увидите их «с самого начала».
Примечание:для первого анализа я настоятельно рекомендую этот инструмент VMmap
(SysInternals).
выводы:
при применении флага LAA к вашему 32-битному исполняемому файлу обязательно полностью протестировать его на ОС x64 с помощью TopDown. AllocationPreference
комплект переключателей.
по вопросам в ваш собственный код возможно, вы сможете их исправить.
просто назову один очень очевидный пример:используйте целые числа без знака вместо целых чисел со знаком для указателей на память.
при возникновении проблем с сторонний модулей нужно попросить автора исправить его ошибки.если это не сделано, вам лучше удалить флаг LargeAddressAware из вашего исполняемого файла.
примечание по тестированию:
параметр реестра MemTopDown не дает желаемых результатов для модульные тесты которые выполняются «программой запуска тестов», которая сама является нет LAA включен.
видеть: Модульное тестирование совместимости с x86 LargeAddressAware
ПС:
Также очень «связанным» и весьма интересным является переход с 32-битного кода на 64-битный.
примеры см.:
- О чем мне, как программисту, нужно беспокоиться при переходе на 64-битную версию Windows?
- https://www.sec.cs.tu-bs.de/pubs/2016-ccs.pdf (вдвое больше битов, в два раза больше проблем)
Другие советы
Потому что большая часть устаревшего кода написана с расчетом на то, что «отрицательные» указатели недействительны.Все, что находится в верхних двух ГБ 32-битного процесса, имеет установленный старший бит.
Таким образом, Microsoft гораздо проще перестраховаться и потребовать, чтобы приложения, которым (а) требуются все 4 ГБ и (б) были разработаны и протестированы в сценарии с большим объемом памяти, просто установили этот флаг.
Это не так уж и сложно, как вы заметили.
Рэймонд Чен - в своем блоге Старая новая вещь - освещает проблемы с включением для всех (32-битных) приложений.
Нет, «устаревший код» в этом контексте (C/C++) — это не только код, который играет ужасные трюки со старшим разрядом указателей.
Он также включает в себя весь код, который использует int для хранения разницы между двумя указателями или длиной области памяти вместо использования правильного типа size_t:Подписанное 'int' имеет 31 бит и не может обрабатывать значения размером более 2 Гб.
Чтобы исправить большую часть вашего кода, нужно просмотреть его и исправить. все из тех безобидный предупреждения о «смешении подписанных и беззнаковых».Он должен выполнить значительную часть работы, по крайней мере, если вы не определили функцию, в которой аргумент типа int на самом деле является длиной памяти.
Однако этот «устаревший код», вероятно, видимо работать долго, даже если ничего не исправлять.
Сломается только тогда, когда в одном блоке выделишь больше 2 Гб.Или когда вы сравниваете два несвязанных указателя, находящихся на расстоянии более 2 Гб друг от друга.
Поскольку сравнение несвязанных указателей в любом случае технически является неопределенным поведением, вы не встретите так много кода, который это делает (но вы никогда не можете быть уверены).
И очень часто, даже если в общей сложности вам требуется более 2 ГБ, ваша программа фактически никогда не выделяет больше этого количества.Фактически, в Windows даже с LARGEADDRESSAWARE вы не сможете по умолчанию выделить столько памяти, учитывая способ организации памяти.Вам придется перетасовать системную DLL, чтобы получить непрерывный блок размером более 2 ГБ.
Но законы Мерфи говорят о таком коде. воля однажды сломается, просто это произойдет очень долго после того, как вы включили LARGEADDRESSAWARE без проверки, и когда никто не вспомнит, что это было сделано.