我们需要将其中一个可执行文件与这个标志链接起来,因为它使用了大量的内存。
但为什么给一个EXE文件的特殊处理。 为什么不标准化/ LARGEADDRESSAWARE?
所以问题是:使用/ LARGEADDRESSAWARE有什么问题,即使你不需要它。 为什么不把它用作所有EXE文件的标准?
LargeAddressAware
标志应用于你的32位可执行文件, LargeAddressAware
一个定时炸弹 ! 通过设置这个标志, 你正在作证的操作系统:
是的,我的应用程序(和运行时加载的所有DLL)可以处理高达4 GB的内存地址。
所以不要将进程的VAS限制为2 GB,而是解锁全部(4 GB)“。
但你能保证吗?
你是否承担你的流程可能使用的所有系统DLL,微软可再发行组件和第三方模块的责任?
通常情况下,内存分配以低到高的顺序返回虚拟地址。 所以,除非你的进程消耗了大量的内存(或者它有一个非常分散的虚拟地址空间),否则它将永远不会使用2GB边界以外的地址。 这是隐藏有关高地址的错误。
如果这样的错误存在,他们很难识别。 他们会零星地出现“迟早”。 这只是时间问题。
幸运的是,在Windows OS中内置了一个非常方便的系统级交换机:
出于测试目的使用MEM_TOP_DOWN注册表设置。
这迫使所有的内存分配从上到下,而不是正常的自下而上。
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Memory Management] "AllocationPreference"=dword:00100000
(这是十六进制0x100000,当然需要Windows重启)
通过启用此开关,您将可以“更快”地识别问题,而不是“以后”。 理想情况下,你会看到他们“从头开始”。
边注:首先分析我强烈推荐工具VMmap
( VMmap
)。
将LAA标志应用于32位可执行文件时,必须在配有TopDown AllocationPreference
开关的x64操作系统上进行完全测试。
对于您自己的代码中的问题, 您可能可以修复它们。
仅举一个非常明显的例子:使用无符号整数代替内存指针的有符号整数。
当遇到与第三方模块有关的问题时,您需要请作者修复他的错误。 除非这样做,否则最好从可执行文件中删除LargeAddressAware标志。
测试说明:
MemTopDown注册表开关没有达到由“测试运行器”本身不是 LAA启用单元测试所需的结果。
请参阅: 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位,并且不能处理超过2Gb的值。
处理好你的代码的一个好办法就是去掉它,纠正所有这些无害的 “混合签名和未签名”警告。 它应该做好工作的一部分,至少如果你没有定义函数,其中int类型的参数实际上是一个内存长度。
然而,即使你没有任何改正,“遗留代码”可能会在一段时间内正常工作。
只有当您在一个区块中分配超过2 Gb的数据时才会中断。 或者当你比较两个互不超过2Gb的无关指针时。
比较无关的指针在技术上是一个未定义的行为,你不会遇到那么多的代码(但你永远不能确定)。
而且,即使总共需要2Gb以上,您的程序实际上也不会使单个分配大于该分配。 事实上,在Windows中,即使使用LARGEADDRESSAWARE,在内存组织方式上也不能默认分配这么多。 你需要拖动系统DLL来获得超过2Gb的连续块
但是Murphy的定律说有一天会有一些代码会被打破,只是在没有检查的情况下启用LARGEADDRESSAWARE,以及什么时候没有人会记得这一切已经完成了。