将 /LARGEADDRESSAWARE 用于 32 位 Windows 可执行文件的缺点?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2288728/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Drawbacks of using /LARGEADDRESSAWARE for 32 bit Windows executables?
提问by Arve
We need to link one of our executables with this flag as it uses lots of memory.
But why give one EXE file special treatment. Why not standardize on /LARGEADDRESSAWARE?
我们需要用这个标志链接我们的一个可执行文件,因为它使用大量内存。
但是为什么要对一个EXE文件进行特殊处理。为什么不标准化 /LARGEADDRESSAWARE?
So the question is: Is there anything wrong with using /LARGEADDRESSAWARE even if you don't need it. Why not use it as standard for all EXE files?
所以问题是:即使您不需要它,使用 /LARGEADDRESSAWARE 有什么问题。为什么不将其用作所有 EXE 文件的标准?
回答by Opmet
blindly applying the LargeAddressAware
flag to your 32bit executable deploys a ticking time bomb!
盲目地将LargeAddressAware
标志应用到您的 32 位可执行文件会部署一个定时炸弹!
by setting this flag youare testifying to the OS:
通过设置此标志,您正在向操作系统作证:
yes, my application (and all DLLs being loaded during runtime) can cope with memory addresses up to 4 GB.
so don't restrict the VAS for the process to 2 GB but unlock the full range (of 4 GB)".
是的,我的应用程序(以及在运行时加载的所有 DLL)可以处理高达 4 GB 的内存地址。
所以不要将进程的 VAS 限制为 2 GB,而是解锁整个范围(4 GB)”。
but can you really guarantee?
do you take responsibility for all the system DLLs, microsoft redistributables and 3rd-party modules your process may use?
但你真的能保证吗?
您是否对您的进程可能使用的所有系统 DLL、Microsoft 可再发行组件和第 3 方模块负责?
usually, memory allocation returns virtual addresses in low-to-high order. so, unless your process consumes a lot of memory (or it has a very fragmented virtual address space), it will never use addresses beyond the 2 GB boundary. this is hiding bugs related to high addresses.
通常,内存分配以低到高的顺序返回虚拟地址。因此,除非您的进程消耗大量内存(或者它的虚拟地址空间非常碎片化),否则它永远不会使用超过 2 GB 边界的地址。这是隐藏与高地址相关的错误。
if such bugs exist they are hard to identify. they will sporadically show up "sooner or later". it's just a matter of time.
如果存在此类错误,则很难识别。他们“迟早”会偶尔出现。这只是时间问题。
luckily there is an extremely handy system-wide switch built into the windows OS:
for testing purposes use the MEM_TOP_DOWN registry setting.
this forces all memory allocations to go from the top down, instead of the normal bottom up.
幸运的是,Windows 操作系统中内置了一个非常方便的系统范围的开关:
出于测试目的,请使用 MEM_TOP_DOWN 注册表设置。
这会强制所有内存分配自上而下,而不是正常的自下而上。
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Memory Management]
"AllocationPreference"=dword:00100000
(this is hex 0x100000. requires windows reboot, of course)
(这是十六进制 0x100000。当然需要重新启动 Windows)
with this switch enabled you will identify issues "sooner" rather than "later". ideally you'll see them "right from the beginning".
启用此开关后,您将“更快”而不是“稍后”识别问题。理想情况下,您会“从一开始”就看到它们。
side note: for first analysis i strongly recommend the tool VMmap
(SysInternals).
旁注:对于第一次分析,我强烈推荐该工具VMmap
(SysInternals)。
conclusions:
结论:
when applying the LAA flag to your 32bit executable it is mandatory to fully test it on a x64 OS with the TopDown AllocationPreference
switch set.
将 LAA 标志应用于 32 位可执行文件时,必须在 x64 操作系统上使用自上而下AllocationPreference
开关设置对其进行全面测试。
for issues in your own codeyou may be able to fix them.
just to name one very obvious example: use unsigned integers instead of signed integers for memory pointers.
对于您自己代码中的问题,您可以修复它们。
举一个非常明显的例子:使用无符号整数代替有符号整数作为内存指针。
when encountering issues with 3rd-partymodules you need to ask the author to fix his bugs. unless this is done you better remove the LargeAddressAware flag from your executable.
当遇到第 3 方模块的问题时,您需要要求作者修复他的错误。除非这样做,否则最好从可执行文件中删除 LargeAddressAware 标志。
a note on testing:
关于测试的说明:
the MemTopDown registry switch is not achieving the desired results for unit teststhat are executed by a "test runner" that itself is notLAA enabled.
see: Unit Testing for x86 LargeAddressAware compatibility
对于由本身未启用 LAA的“测试运行程序”执行的单元测试,MemTopDown 注册表开关未达到预期结果。
请参阅:x86 LargeAddressAware 兼容性的单元测试
PS:
also very "related" and quite interesting is the migration from 32bit code to 64bit.
for examples see:
PS:
从 32 位代码到 64 位代码的迁移也非常“相关”并且非常有趣。
示例见:
- As a programmer, what do I need to worry about when moving to 64-bit windows?
- https://www.sec.cs.tu-bs.de/pubs/2016-ccs.pdf(twice the bits, twice the trouble)
回答by Chris Becke
Because lots of legacy code is written with the expectation that "negative" pointers are invalid. Anything in the top two Gb of a 32bit process has the msb set.
因为许多遗留代码是在期望“负”指针无效的情况下编写的。32 位进程的前两个 Gb 中的任何内容都设置了 msb。
As such, its far easier for Microsoft to play it safe, and require applications that (a) need the full 4Gb and (b) have been developed and tested in a large memory scenario, to simply set the flag.
因此,微软更容易安全地使用它,并且需要 (a) 需要完整 4Gb 和 (b) 已经在大内存场景中开发和测试的应用程序,只需设置标志。
It's not - as you have noticed - that hard.
正如你所注意到的,这并不难。
Raymond Chen - in his blog The Old New Thing- covers the issues with turning it on for all (32bit) applications.
Raymond Chen - 在他的博客The Old New Thing- 介绍了为所有(32 位)应用程序打开它的问题。
回答by jmd
No, "legacy code" in this context (C/C++) is not exclusively code that plays ugly tricks with the MSB of pointers.
不,这种上下文中的“遗留代码”(C/C++)不仅仅是用指针的 MSB 玩丑陋技巧的代码。
It also includes all the code that uses 'int' to store the difference between two pointer, or the length of a memory area, instead of using the correct type 'size_t' : 'int' being signed has 31 bits, and can not handle a value of more than 2 Gb.
它还包括所有使用'int'来存储两个指针之间的差异或内存区域长度的代码,而不是使用正确的类型'size_t':'int'被签名有31位,无法处理大于 2 Gb 的值。
A way to cure a good part of your code is to go over it and correct allof those innocuous"mixing signed and unsigned" warnings. It should do a good part of the job, at least if you haven't defined function where an argument of type int is actually a memory length.
治愈大部分代码的一种方法是检查它并纠正所有那些无害的“混合签名和未签名”警告。它应该可以很好地完成工作,至少如果您还没有定义函数,其中 int 类型的参数实际上是内存长度。
However that "legacy code" will probably apparentlywork right for quite a while, even if you correct nothing.
但是,这种“遗留代码”可能会明显地权工作相当长一段时间,即使你什么都不正确。
You'll only break when you'll allocate more than 2 Gb in one block. Or when you'll compare two unrelated pointers that are more than 2 Gb away from each other.
As comparing unrelated pointers is technically an undefined behaviour anyway, you won't encounter that much code that does it (but you can never be sure).
And very frequently even if in total you need more than 2Gb, your program actually never makes single allocations that are larger than that. In fact in Windows, even with LARGEADDRESSAWARE you won't be able by default to allocate that much given the way the memory is organized. You'd need to shuffle the system DLL around to get a continuous block of more than 2Gb
只有当您在一个块中分配超过 2 Gb 时,您才会中断。或者当您比较两个彼此相距超过 2 Gb 的不相关指针时。
由于比较不相关的指针在技术上无论如何都是未定义的行为,因此您不会遇到那么多执行此操作的代码(但您永远无法确定)。
并且非常频繁,即使您总共需要超过 2Gb,您的程序实际上也不会进行比这更大的单个分配。事实上,在 Windows 中,即使使用 LARGEADDRESSAWARE,鉴于内存的组织方式,默认情况下您也无法分配那么多。您需要调整系统 DLL 以获得超过 2Gb 的连续块
But Murphy's laws says that kind of code willbreaks one day, it's just that it will happen very long after you've enable LARGEADDRESSAWARE without checking, and when nobody will remember this has been done.
但是墨菲定律说这种代码总有一天会崩溃,只是在您启用 LARGEADDRESSAWARE 而不检查之后很长时间就会发生这种情况,并且没有人会记得已经这样做了。