为什么用{:p}打印的内存地址比我的RAM规格大得多?

Joh*_*ith 7 memory rust

我想打印变量的内存位置(地址):

let x = 1;
println!("{:p}", &x);
Run Code Online (Sandbox Code Playgroud)

这将打印0x7fff51ef6380十进制的十六进制值140734568031104.

我的电脑有16GB的RAM,为什么这么大的数字呢?x64架构是否使用大间隔序列而不是简单的1增量来访问内存位置?

在x86中,通常第一个位置从0开始,然后是1,2,等等.因此,您可以拥有的最高数字大约为40亿,因此地址编号始终等于或小于40亿.

为什么x64不是这种情况?

Luk*_*odt 11

你在这里看到的是虚拟内存的影响.内存管理很难,当操作系统和数百个进程必须共享内存时,内存管理变得更加困难.为了处理这种巨大的复杂性,使用了虚拟内存的概念.我将简要介绍一下这里的基础知识; 这个话题要复杂得多,你也应该把它读到别的地方.

在大多数现代计算机上,每个进程都认为它拥有(几乎)完整的内存空间.但是进程从不处理物理地址,而是处理虚拟地址.每次进程实际从内存中读取时,这些虚拟地址都会映射到物理地址.地址的这种转换由所谓的MMU(存储器管理单元)完成.如何映射地址的规则由操作系统设置.

启动PC时,操作系统会创建初始映射.每次启动进程时,操作系统都会向进程添加几片物理内存,并相应地修改映射.这样,这个过程就有了记忆.

在x86_64上,地址空间为64位宽,因此每个进程都认为它拥有所有这些2 ^ 64个地址.当然,这不是真的:

  1. 世界上没有一台拥有那么多内存的PC.(事实上​​,今天大多数CPU 只能使用280 TB的RAM,因为它们内部只能使用48位来寻址物理内存.显然,即使这些280TB也足够了.)
  2. 即使你有那么多内存,也有其他进程使用那部分内存.

那么当你尝试读取未映射的地址时会发生什么(在64位的地址中,绝大多数是地址)?MMU触发页面错误.这使CPU通知操作系统处理此问题.

我的意思是在x86中,通常第一个位置从0开始,然后是1,2,等等,所以你可以拥有的最高数字大约是40亿.

这是事实,但如果您的x86系统的RAM少于4GB,也是如此.虚拟内存已存在很长时间了.


这就是为什么你看到这么大的地址的简短摘要.请再次注意,我在这里隐藏了许多细节.


Pet*_*des 7

程序使用的指针位于虚拟地址空间中.x86-64使用64位指针.这是AMD64的主要目标之一,同时添加了更多的整数和XMM寄存器.你是对的,i386只有32位指针,每个进程只能覆盖4GB的地址空间.

0x7fff51ef6380 看起来像一个堆栈指针,我猜这个代码是有道理的.

Linux on x86-64(例如)将堆栈置于较低规范地址范围的顶部:当前x86-64硬件仅实现48位虚拟地址,这是防止软件依赖它的机制.这允许将来扩展地址空间而不破坏软件.

系统中的物理RAM量与此无关.你会在x86-64系统上看到(大约)相同的数字,内存为128MB,+/ - 堆栈地址空间布局随机化(ASLR).