不管在 32 位 Windows 上还是在 64 位 Windows 上,32 位的应用程序都只能使用最大 2GB 的内存,这是我们司空见惯的一个设定。但其实 Windows 提供了一些方法让我们打破这样的设定,使程序使用大于 2GB 的内存。
为什么 32 位程序只能使用最大 2GB 内存?
32 位寻址空间只有 4GB 大小,于是 32 位应用程序进程最大只能用到 4GB 的内存。然而,除了应用程序本身要用内存,操作系统内核也需要使用。应用程序使用的内存空间分为用户空间和内核空间,每个 32 位程序的用户空间可独享前 2GB 空间(指针值为正数),而内核空间为所有进程共享 2GB 空间(指针值为负数)。所以,32 位应用程序实际能够访问的内存地址空间最多只有 2GB。
让 32 位程序使用大于 2GB 内存的三种方法
推荐:dotnetCampus.LargeAddressAware 库
详见:为 .NET Core / Framework 程序开启大内存感知(LargeAddressAware),使 32 位程序支持最多 4GB 的用户空间内存
editbin
这是 Visual Studio 2017 采用的做法。我们需要使用到两个工具——editbin
和 dumpbin
。前者用于编辑我们编译生成好的程序使之头信息中声明支持大于 2GB 内存,后者用于查看程序的头信息验证我们是否改好了。
编辑一个程序使之声明支持大于 2GB 内存的命令是:
1
editbin /largeaddressaware xxx.exe
其中,xxx.exe
是我们准备修改的程序,可以使用相对路径或绝对路径(如果路径中出现空格记得带引号)。
验证这个程序是否改好了的命令是:
1
dumpbin /headers xxx.exe | more
同样,xxx.exe
是我们刚刚改好准备检查的程序,可以使用相对路径或绝对路径。
editbin 改之前和改之后用 dumpbin 查看我们的程序头信息,得到下面两张图:
注意到 FILE HEADER VALUES
块的倒数第二行多出了 Application can handle large (>2GB) addresses
。
如果没发现,一定是你命令执行中发生了错误,检查一下吧!最容易出现的错误是执行后发现根本就没有这个命令。是的,editbin
命令从哪里来呢?可以在开始菜单中的 Visual Studio 文件夹中查找 Developer Command Prompt for VS 2017,运行这个启动的命令行中就带有 editbin 和 dumpbin。
如果希望能够在 Visual Studio 编译的时候自动调用这个工具,请参见:LargeAddressAware Visual Studio 2015 C#。
编译成 AnyCPU (Prefer 32-bit)
这是本文更推荐的做法,也是最简单的做法。方法是打开入口程序集的属性页,将“目标平台”选为“AnyCPU”,然后勾选“首选 32 位”。需要注意的是,这种生成方式是 .NET Framework 4.5 及以上版本才提供的。
至于 AnyCPU (Prefer 32-bit) 和 x86 两种生成方式的区别,请参见:WPF 编译为 AnyCPU 和 x86 有什么区别 - 林德熙 和 What is the purpose of the “Prefer 32-bit” setting in Visual Studio 2012 and how does it actually work?。
声明支持大于 2GB 内存后,能使用多少内存?
对于 32 位操作系统,程序依然只能使用 2GB 内存,除非开启了 /3GB
开关,开启方法详见:/3GB。开启后,应用程序的用户态将可以使用 3GB 内存,但内核态将只能使用 1GB 内存。微软认为,是否打开 /3GB
开关是计算机设备开发商需要做的事情,开发商也需要自己测试开启后驱动程序的性能表现和稳定性。
对于 64 位操作系统,Windows 将很豪放地将 4GB 全部贡献给这样的程序,因为系统自己已经有更多的内存寻址空间可以使用了,没必要跟 32 位应用程序抢占寻址空间。
参考资料
- AnyCPU (32bit preferred)
- IMAGE_FILE_LARGE_ADDRESS_AWARE
- Memory Limits for Windows and Windows Server Releases
- Getting 32-bit application to use more than 2GB on 64-bit Windows 7?
- /LARGEADDRESSAWARE (Handle Large Addresses)
- Why 2 GB memory limit when running in 64 bit Windows?
- Pushing the Limits of Windows: Paged and Nonpaged Pool
- Can a 32bit process access more memory on a 64bit windows OS?
- /3GB
- editbin/dumpbin
editbin /largeaddressaware xxx.exe
dumpbin /headers xxx.exe | more
- verify if largeAddressAware is in effect?
- LargeAddressAware Visual Studio 2015 C#
本文会经常更新,请阅读原文: https://blog.walterlv.com/windows/2017/09/12/32bit-application-use-large-memory.html ,以避免陈旧错误知识的误导,同时有更好的阅读体验。
本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。欢迎转载、使用、重新发布,但务必保留文章署名 吕毅 (包含链接: https://blog.walterlv.com ),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请 与我联系 ([email protected]) 。