c# - 可能 64 位 Windows 分配虚拟内存超过 7FFF'FFFF'FFFF?
问题描述
语境
我正在升级 .NET 库以支持 64 位。该库直接在 Windows 上其他进程的内存中执行各种操作。我必须在两种类型IntPtr
(最大正值 7FFF'FFFF'FFFF'FFFF)或UIntPtr
(最大正值 FFFF'FFFF'FFFF'FFFF)之间进行选择来处理我的内存指针。网上有很多关于这两者的信息。IntPtr
似乎是事实上商定的选择,因为它符合 CLS,并且大多数 .NET API 都依赖于它(参考Marshal
来自InteropServices
)。
问题
我决定打开一个 64 位进程并检查分配的内存区域,以及进程中加载的模块,看看使用UIntPtr
(addresses > 7FFF'FFFF'FFFF'FFFF) 支持无符号指针是否有价值。如下图所示,内存地址似乎没有加载符号,也没有分配超过 7FFF'FFFF'FFFF 的内存。这样做有什么具体原因吗?在某些情况下,Windows 是否可以分配超过该值的内存区域?
解决方案
在 Windows 中每个进程只有 8TB 的地址空间,因此用户代码的上限是 0x7FF'FFFF'FFFF
进程可用的虚拟地址范围称为进程的虚拟地址空间。每个用户模式进程都有自己的私有虚拟地址空间。对于 32 位进程,虚拟地址空间通常是 2 GB 范围 0x00000000 到 0x7FFFFFFF。对于 64 位进程,虚拟地址空间是 0x000'00000000 到 0x7FF'FFFFFFFF 的 8 TB 范围。虚拟地址范围有时称为虚拟内存范围。
此图说明了虚拟地址空间的一些关键特性。
https://docs.microsoft.com/en-us/windows-hardware/drivers/gettingstarted/virtual-address-spaces
上面的 248TB 属于内核态,总共有 256TB 的地址空间,由48 位寻址。这意味着最高可能的正地址是 2 47 -1 = 0x7FFF'FFFF'FFFF
在 64 位 Windows 中,虚拟地址空间的理论量为 2^64 字节(16 艾字节),但实际上只使用了 16 艾字节范围的一小部分。从 0x000'00000000 到 0x7FF'FFFFFFFF 的 8 TB 范围用于用户空间,从 0xFFFF0800'00000000 到 0xFFFFFFFF'FFFFFFFF 的 248 TB 范围的一部分用于系统空间。
更新:
如下所述,在 Windows 8.1 和 Windows Server 2012 R2 或更高版本中,用户/内核地址空间拆分为 128/128TB,总计相同的 256TB 空间
重要部分是 48 位宽,可能是因为大多数当前 x86-64 实现使用 48 位虚拟地址
AMD64 架构的原始实现实现了 40 位物理地址,因此可以寻址高达 1 TB(2 40字节)的 RAM。AMD64 架构的当前实现(从 AMD 10h 微架构开始)将其扩展到 48 位物理地址,因此可以寻址高达 256 TB 的 RAM。该架构允许将来将其扩展到 52 位(受页表条目格式的限制);这将允许寻址多达 4 PB 的 RAM。
推荐阅读
- excel - 如何读取网络连接窗口上的计时器值?
- javascript - 如何访问另一个 Mongoose 方案对象数组中定义的数组元素?
- c# - 是否可以使用 c# 编译器添加 PostSharp 进行动态编译
- algorithm - 几条线段的最小迹线的高效算法
- ios - 对于没有 UISceneDelegate 的项目,iOS14 上的 UIKit 故障
- angular - 如何在角度库中添加 svg 图像?
- jquery - 在引导程序 datetimepicker 中选择时间后关闭日期时间选择器日历
- python - 如何加入 DataFrame 组中的列值?
- angularjs - 在使用 RXJS pluck() 之前如何检查属性是否存在?
- webrtc - 如何使用 peerjs 实现一对多视频广播