首页 > 解决方案 > 可能 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 是否可以分配超过该值的内存区域?

作弊引擎上的内存分配(64 位)

标签: c#windowsx86-64virtual-memoryinternals

解决方案


在 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。

https://en.wikipedia.org/wiki/X86-64#Architectural_features


推荐阅读