对于32位Windows可执行文件使用/ LARGEADDRESSAWARE的缺点是什么?

Arv*_*rve 32 memory windows memory-management virtual-address-space

我们需要将其中一个可执行文件与此标志链接,因为它使用大量内存.
但为什么要给一个EXE文件特殊处理.为什么不标准化/ LARGEADDRESSAWARE?

所以问题是:即使你不需要它,使用/ LARGEADDRESSAWARE也有什么问题.为什么不将它用作所有EXE文件的标准?

Opm*_*met 46

盲目地将LargeAddressAware旗帜应用于你的32位可执行文件会部署定时炸弹!

通过设置此标志,将向操作系统作证:

是的,我的应用程序(以及在运行时加载的所有DLL)可以处理高达4 GB的内存地址.
所以不要将进程的VAS限制为2 GB,而是解锁全范围(4 GB)".

但你能真的保证吗?
您是否对您的进程可能使用的所有系统DLL,Microsoft可再发行组件和第三方模块负责?

通常,内存分配以低到高的顺序返回虚拟地址.因此,除非您的进程占用大量内存(或者它具有非常分散的虚拟地址空间),否则它将永远不会使用超过2 GB边界的地址.这是隐藏与高地址相关的错误.

如果存在这样的错误,则很难识别.他们会偶尔出现"迟早".这只是时间问题.

幸运的是,Windows操作系统内置了一个非常方便的系统范围开关:
出于测试目的,使用MEM_TOP_DOWN注册表设置.
这会强制所有内存分配从上到下,而不是正常的自下而上.

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Memory Management]
"AllocationPreference"=dword:00100000
Run Code Online (Sandbox Code Playgroud)

(这是十六进制0x100000.当然需要Windows重启)

启用此开关后,您将"更快"而不是"更晚"识别问题.理想情况下,你会"从一开始就"看到它们.

旁注:首先分析我强烈推荐使用该工具VMmap(SysInternals).

结论:

将LAA标志应用于32位可执行文件时,必须在AllocationPreference设置了TopDown 开关的x64操作系统上对其进行全面测试.

对于您自己的代码中的问题,可以修复它们.
仅举一个非常明显的例子:使用无符号整数而不是有符号整数作为内存指针.

当遇到第三方模块的问题时,您需要让作者修复他的错误.除非这样做,否则最好从可执行文件中删除LargeAddressAware标志.


关于测试的说明:

MemTopDown注册表开关未实现由"测试运行程序"执行的单元测试所需的结果,该测试运行程序本身启用LAA.
请参阅:x86 LargeAddressAware兼容性的单元测试


PS:
也非常"相关",非常有趣的是从32位代码迁移到64位.
例如见:


Chr*_*cke 12

因为编写了大量遗留代码,期望"否定"指针无效.32位进程的前两个Gb中的任何内容都设置了msb.

因此,微软更容易安全地使用它,并且要求应用程序(a)需要完整的4Gb并且(b)已经在大型内存场景中开发和测试,以简单地设置标志.

它不是 - 你已经注意到 - 那很难.

Raymond Chen - 在他的博客The Old New Thing中 - 涵盖了为所有(32位)应用程序启用它的问题.


jmd*_*jmd 6

不,这个上下文中的"遗留代码"(C/C++)并不是专门用指针MSB播放丑陋技巧的代码.

它还包括使用'int'来存储两个指针之间的差异或内存区域长度的所有代码,而不是使用正确的类型'size_t':'int'被签名有31位,并且无法处理值大于2 Gb.

解决代码的一部分的一种方法是检查它并纠正所有那些无害的 "混合签名和未签名"警告.它应该做好工作的一部分,至少如果你没有定义函数,其中int类型的参数实际上是一个内存长度.

然而,即使你没有做任何改正,"遗留代码"可能显然可以正常工作一段时间.

只有当你在一个区块中分配超过2 Gb时才会中断.或者当你比较两个彼此远离2 Gb以上的无关指针时.
因为比较不相关的指针在技术上是一种未定义的行为,你不会遇到那么多的代码(但你永远无法确定).
而且即使总共需要超过2Gb,您的程序实际上也从不进行大于此的单个分配.实际上在Windows中,即使使用LARGEADDRESSAWARE,在默认情况下,根据内存的组织方式,您也无法分配那么多.您需要将系统DLL混乱以获得超过2Gb的连续块

但墨菲的法律规定,有一天代码破坏,只是在你没有检查就启用了LARGEADDRESSAWARE之后很久就会发生这种情况,并且当没人会记住这已经完成时.