如果你不做特殊处理,把你的项目以 x86 的架构进行编译,那么你的应用程序在 Windows 上最多只能使用 2GB 的内存(地址空间)。如果你的项目使用 .NET Framework 框架,那么现行有很多简单的方法来帮你实现大内存感知,但 .NET Core 框架下却没有。所以我写了一个库 dotnetCampus.LargeAddressAware,帮助你轻松实现 32 位程序的大内存感知。
dotnetCampus.LargeAddressAware 库
无论你是 .NET Framework 程序还是 .NET Core 程序,只要在你的项目中安装 dotnetCampus.LargeAddressAware 即可立享最高可达 4GB 的用户空间内存。
1 2 3 | <ItemGroup> <PackageReference Include="dotnetCampus.LargeAddressAware" Version="1.0.0" /> </ItemGroup> |
---|
效果
应用程序 | 操作系统 | 是否开启大内存感知 | 最大可使用的用户空间内存 |
---|---|---|---|
32-bit | 32-bit | ❌ | 2GB |
32-bit | 64-bit | ❌ | 2GB |
32-bit | 32-bit | ✔️ | 3GB |
32-bit | 64-bit | ✔️ | 4GB |
原理
我在 2017 年写的一篇博客(使 32 位程序使用大于 2GB 的内存)中就已经介绍过 32 位程序开启大内存感知的原理和方法了,不过因为一开始我自己也懂得不多,所以写得比较简单。后来也根据自己新的理解也填充了不少内容,但是当初取的标题和内容真的很难被搜到,而且侧重点在方法上。所以现在重写了现在的这篇新的,侧重在让懒用户快速上手,让深度用户快速理解上。
32 位寻址空间只有 4GB 大小,于是 32 位应用程序进程最大只能用到 4GB 的内存。然而,除了应用程序本身要用内存,操作系统内核也需要使用。应用程序使用的内存空间分为用户空间和内核空间,每个 32 位程序的用户空间可独享前 2GB 空间(指针值为正数),而内核空间为所有进程共享 2GB 空间(指针值为负数)。所以,32 位应用程序实际能够访问的内存地址空间最多只有 2GB。
在应用程序的 PE 头上,有一个应用程序是否感知大内存的标记 LARGEADDRESSAWARE
。当 32 位操作系统识别到此标记时,会为其提供 3GB 的用户空间;当 64 位操作系统识别到此标记时,会为其提供 4GB 的用户空间,即用户态完全用满 32 位的寻址空间。
其他开启 LARGEADDRESSAWARE
的方法
不推荐的方法:仅适用于 .NET Framework 的旧方法
当时的那篇博客中,我提到过可通过编译成 AnyCPU (Prefer 32-bit) 来实现大内存感知,这也是最简单的方式,被 .NET Framework 自带。方法是修改 csproj 文件,加上这两句:
1 2 3 4 5 | <PropertyGroup> <!-- 此方法被废弃,因为不支持 .NET Core --> <PlatformTarget>AnyCPU</PlatformTarget> <Prefer32Bit>true</Prefer32Bit> </PropertyGroup> |
---|
可惜,此方法只适用于 .NET Framework 程序,不适用于 .NET Core 程序!因为 .NET Core 框架下编译时,是直接忽略 Prefer32Bit
的!.NET Core 下大内存感知确实是有了,但生成的却是 AMD64 程序,无法在 32 位系统下运行。
不推荐的方法:使用 EditBin 的原始方法
如果还想用自带的方法来完成大内存感知的开启的话,我们只能选用 Visual Studio 自带的 editbin 了。方法是打开 Visual Studio 自带的终端,然后在里面输入:
1 | editbin /largeaddressaware xxx.exe |
---|
方法本身其实是非常好的,毕竟是 Visual Studio 自带的工具链。但需要手工执行就是一个大坑!你怎么能保证每次发布前要运行一下这个命令呢?
检查是否已开启大内存感知
我在之前的博客中提到可以使用 Visual Studio 自带的 dumpbin 工具来检查是否开启了大内存感知:
1 | dumpbin /headers xxx.exe | more |
---|
但是,我们有更直观的 dnSpy 为什么还要用命令行来临时查看呢?相信你早就注意到前面我已经贴了一张 dnSpy 检查大内存感知的图了。
参考资料
- AnyCPU (32bit preferred)
- What is the purpose of the “Prefer 32-bit” setting in Visual Studio 2012 and how does it actually work?
- WPF 编译为 AnyCPU 和 x86 有什么区别 - 林德熙
- 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
- /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/post/how-to-enable-large-address-aware-for-net-apps.html ,以避免陈旧错误知识的误导,同时有更好的阅读体验。
本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。欢迎转载、使用、重新发布,但务必保留文章署名 吕毅 (包含链接: https://blog.walterlv.com ),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请 与我联系 ([email protected]) 。