Недостатки использования / LARGEADDRESSAWARE для 32-битных исполняемых файлов Windows? - PullRequest
30 голосов
/ 18 февраля 2010

Нам нужно связать один из наших исполняемых файлов с этим флагом, так как он использует много памяти.
Но зачем отдавать один EXE-файл особой обработке. Почему бы не стандартизировать / LARGEADDRESSAWARE?

Итак, вопрос в том, есть ли что-то не так с использованием / LARGEADDRESSAWARE, даже если оно вам не нужно Почему бы не использовать его как стандартный для всех файлов EXE?

Ответы [ 3 ]

44 голосов
/ 30 марта 2014

вслепую применяя флаг 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 совместимость


PS:
также очень «родственным» и довольно интересным является переход с 32-битного кода на 64-битный.
примеры см .:

11 голосов
/ 18 февраля 2010

Поскольку много унаследованного кода написано с ожиданием того, что «отрицательные» указатели недействительны. Все, что находится в первых двух гигабайтах 32-битного процесса, имеет набор msb.

Таким образом, для Microsoft гораздо проще играть безопасно и требовать, чтобы приложения (а) требовали 4 Гб и (b) были разработаны и протестированы в сценарии с большой памятью, чтобы просто установить флаг.

Это не так - как вы заметили - это сложно.

Раймонд Чен - в своем блоге The Old New Thing - освещает проблемы с включением его для всех (32-битных) приложений.

6 голосов
/ 19 января 2011

Нет, «унаследованный код» в этом контексте (C / C ++) не является исключительно кодом, который играет некрасивые трюки с MSB указателей.

Он также включает в себя весь код, который использует 'int' для хранения разницы между двумя указателями или длиной области памяти, вместо использования правильного типа 'size_t': подписываемый 'int' имеет 31 бит, и не может обрабатывать значение более 2 Гб.

Чтобы вылечить хорошую часть вашего кода, нужно пройти по нему и исправить все из этих безобидных"смешиваний подписанных и неподписанных" предупреждений. Он должен выполнять значительную часть работы, по крайней мере, если вы не определили функцию, в которой аргумент типа int фактически равен длине памяти.

Однако этот «устаревший код», вероятно, будет , по-видимому, работать некоторое время, даже если вы ничего не исправляете.

Вы сломаетесь, только когда выделите более 2 Гб в одном блоке. Или когда вы сравните два не связанных между собой указателя, которые находятся на расстоянии более 2 Гб друг от друга.
Поскольку сравнение несвязанных указателей является технически неопределенным поведением в любом случае, вы не столкнетесь с таким большим количеством кода, который это делает (но вы никогда не можете быть уверены).
И очень часто, даже если в общей сложности вам требуется более 2 ГБ, ваша программа на самом деле никогда не делает одиночные выделения, которые превышают это. На самом деле, в Windows, даже с LARGEADDRESSAWARE, вы не сможете по умолчанию выделять так много, учитывая то, как организована память. Вам нужно будет перетасовать системную DLL вокруг, чтобы получить непрерывный блок более 2 ГБ

Но законы Мерфи гласят, что код будет ломаться однажды, просто это произойдет очень долго после того, как вы включите LARGEADDRESSAWARE без проверки, и когда никто не вспомнит, что это было сделано.

...