我们需要将我们的一个可执行文件与此标志链接,因为它使用大量内存。
但是为什么要给一个EXE文件特殊处理呢。为什么不标准化/LARGEADDRESSAWARE
?
所以问题是:/LARGEADDRESSAWARE
即使你不需要它,使用它有什么问题。为什么不将它用作所有 EXE 文件的标准?
我们需要将我们的一个可执行文件与此标志链接,因为它使用大量内存。
但是为什么要给一个EXE文件特殊处理呢。为什么不标准化/LARGEADDRESSAWARE
?
所以问题是:/LARGEADDRESSAWARE
即使你不需要它,使用它有什么问题。为什么不将它用作所有 EXE 文件的标准?
LargeAddressAware
标志应用于您的 32 位可执行文件会部署一个定时炸弹!通过设置此标志,您正在向操作系统作证:
是的,我的应用程序(以及在运行时加载的所有 DLL)可以处理高达 4 GB 的内存地址。
所以不要将进程的 VAS 限制为 2 GB,而是解锁整个范围(4 GB)”。
但你真的能保证吗?
您是否对您的进程可能使用的所有系统 DLL、Microsoft 可再发行组件和第 3 方模块负责?
通常,内存分配按从低到高的顺序返回虚拟地址。因此,除非您的进程消耗大量内存(或者它具有非常碎片化的虚拟地址空间),否则它永远不会使用超过 2 GB 边界的地址。这是隐藏与高地址相关的错误。
如果存在此类错误,则很难识别。他们会“迟早”偶尔出现。这只是时间问题。
幸运的是,windows 操作系统内置了一个非常方便的系统范围开关:
出于测试目的,请使用 MEM_TOP_DOWN 注册表设置。
这会强制所有内存分配自上而下,而不是正常的自下而上。
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Memory Management]
"AllocationPreference"=dword:00100000
(这是十六进制 0x100000。当然需要重新启动 Windows)
启用此开关后,您将“更快”而不是“稍后”识别问题。理想情况下,您会“从一开始”就看到它们。
旁注:对于第一次分析,我强烈推荐该工具VMmap
(SysInternals)。
将 LAA 标志应用于 32 位可执行文件时,必须在设置了 TopDownAllocationPreference
开关的 x64 操作系统上对其进行全面测试。
对于您自己的代码中的问题,您可以修复它们。
举一个非常明显的例子:使用无符号整数而不是有符号整数作为内存指针。
当遇到与3rd-party模块有关的问题时,您需要要求作者修复他的错误。除非这样做,否则最好从可执行文件中删除 LargeAddressAware 标志。
关于测试的说明:
对于由本身未启用 LAA的“测试运行器”执行的单元测试, MemTopDown 注册表开关没有达到预期的结果。
请参阅:x86 LargeAddressAware 兼容性的单元测试
PS:
从 32 位代码到 64 位的迁移也是非常“相关”且非常有趣的。
示例见:
因为许多遗留代码是在期望“负”指针无效的情况下编写的。32 位进程的前两个 Gb 中的任何内容都设置了 msb。
因此,微软更容易安全行事,并要求 (a) 需要完整 4Gb 和 (b) 已在大内存场景中开发和测试的应用程序,只需设置标志即可。
正如你所注意到的那样,这并不难。
Raymond Chen - 在他的博客The Old New Thing中- 涵盖了为所有(32 位)应用程序打开它的问题。
不,在这种情况下(C/C++)中的“遗留代码”并不是专门用指针的 MSB 玩丑陋把戏的代码。
它还包括所有使用'int'来存储两个指针之间的差异,或者内存区域的长度,而不是使用正确的类型'size_t'的代码:被签名的'int'有31位,无法处理超过 2 Gb 的值。
解决大部分代码的一种方法是检查它并纠正所有那些无害的“混合签名和未签名”警告。它应该可以很好地完成工作,至少如果您没有定义 int 类型的参数实际上是内存长度的函数。
但是,即使您什么都不改正,“遗留代码”也可能会在很长一段时间内正常工作。
只有在一个块中分配超过 2 Gb 时才会中断。或者当您比较两个彼此相距超过 2 Gb 的不相关指针时。
由于比较不相关的指针在技术上无论如何都是未定义的行为,因此您不会遇到那么多代码(但您永远无法确定)。
而且,即使您总共需要超过 2Gb,您的程序实际上也不会进行大于此的单个分配。事实上,在 Windows 中,即使使用 LARGEADDRESSAWARE,您也无法在默认情况下根据内存的组织方式分配那么多。您需要重新调整系统 DLL 以获得超过 2Gb 的连续块
但是墨菲定律说这种代码总有一天会被破坏,只是它会在你启用 LARGEADDRESSAWARE 之后很长时间而不检查,并且没有人会记得这已经完成。