我正在升级.NET库以支持64位。该库直接在Windows上其他进程的内存中执行各种操作。我必须选择两种类型IntPtr
(最大正值7FFF'FFFF'FFFF'FFFF)或UIntPtr
(最大正值FFFF'FFFF'FFFF'FFFF)来处理内存指针。 Web上有很多有关这两者的信息。 IntPtr
似乎是deacto公认的选择,因为它符合CLS,并且大多数.NET API都依赖于此(Marshal
中的InteropServices
)。
我决定打开64位进程,并检查进程中分配的内存区域以及加载的模块,以查看使用UIntPtr
支持无符号指针是否有价值(地址> 7FFF'FFFF'FFFF 'FFFF)。如下图所示,似乎内存地址没有加载符号,也没有在7FFF'FFFF'FFFF上分配内存。是否有这样做的特定原因?在某些情况下,Windows可以在该值上分配内存区域吗?
在Windows中,每个进程只有8TB的地址空间,因此用户代码的上限为0x7FF'FFFF'FFFF
可用于进程的虚拟地址范围称为该进程的虚拟地址空间。每个用户模式进程都有其自己的专用虚拟地址空间。对于32位进程,虚拟地址空间通常为2 GB范围0x00000000到0x7FFFFFFF。对于64位进程,虚拟地址空间是8 TB范围0x000'00000000到0x7FF'FFFFFFFF。虚拟地址范围有时也称为虚拟内存范围。
此图说明了虚拟地址空间的一些关键特征。
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范围的部分用于系统空间。
重要部分是48位宽,可能是因为当前大多数x86-64实现使用48位虚拟地址
AMD64体系结构的原始实现实现了40位物理地址,因此可以寻址高达1 TB(2 40字节)的RAM。 AMD64体系结构的当前实现(从AMD 10h微体系结构开始)将其扩展到48位物理地址,因此可以寻址高达256 TB的RAM。该体系结构允许将来将其扩展到52位(受页表条目格式的限制)。这将允许寻址多达4 PB的RAM。
由于x64的规格,您可以依赖始终适合IntPtr
的用户空间指针。您不能依靠更小的空间。将来,CPU可能会获得更多地址线。在Windows 8和Windows 8.1之间发生这种情况时,没有添加向后兼容性标志。
实际上,在x86中既有正指针又有负指针,但是无论如何,由于IntPtr
处的无芒区域和0x7FFF0000
处的空陷阱范围,将指针存储在0x00000000
中仍然有效。
我不认为您正在尝试做带标记的指针,但是如果您愿意,做带标记的指针的唯一可接受的方法是底部的两位。
在Windows中,最大虚拟内存地址为7FFF'FFFF'FFFF'FFFF,即无法分配超出该地址的内存。从历史上看,AMD和Intel的第一个64位处理器(按照AMD64规范)仅支持48位地址。因此限制了。
在此处查看更多详细信息:http://www.alex-ionescu.com/?p=50和https://blogs.technet.microsoft.com/markrussinovich/2008/11/17/pushing-the-limits-of-windows-virtual-memory/