![虚拟内存与进程的虚拟地址空间有关吗?](https://linux22.com/image/1292742/%E8%99%9A%E6%8B%9F%E5%86%85%E5%AD%98%E4%B8%8E%E8%BF%9B%E7%A8%8B%E7%9A%84%E8%99%9A%E6%8B%9F%E5%9C%B0%E5%9D%80%E7%A9%BA%E9%97%B4%E6%9C%89%E5%85%B3%E5%90%97%EF%BC%9F.png)
据我了解,分页是一种内存管理技术,它允许计算机将数据从辅助存储器带到主存储器以执行进程。它给进程留下一个印象,即它有一个大的连续地址空间(虚拟地址空间)。页表将进程的虚拟地址映射到物理地址。虚拟地址是 CPU 使用的地址。当需要访问内存时,使用转换过程从页表获取与虚拟地址相对应的物理地址(RAM 中的实际地址)。虚拟内存的概念是 - 当 CPU 需要的内存多于现有的物理内存时,操作系统会将辅助存储器的一部分用作 RAM。
当我尝试将这两个概念联系起来时,我感到很困惑。我的问题是 - 虚拟内存是否与进程的虚拟地址空间相关。进程的虚拟地址空间是否真的存在于虚拟内存中?但是,由于虚拟内存实际上是辅助存储的一部分,这怎么可能呢?或者进程的虚拟地址空间位于 RAM 中?进程的虚拟地址空间和物理地址空间是否都存在于 RAM 中?请澄清一下。
答案1
虚拟内存和分页不应与页面文件(也称为交换文件)
这两个概念确实是有联系的,但是还是有区别的。
虚拟内存是指进程的虚拟地址空间:每个进程都“认为”它有一个专用的 32 位(或 64 位)地址空间,但实际上并没有——可能有些页面没有实际上存在于内存中,或者可能存在于不同的物理地址,但进程并不关心。
这方法实现这一点的方法称为分页:每当进程访问内存时,内存管理单元都会通过查找物理页面RAM 对应于虚拟页面内存。(页面是内存管理的较大单位,通常为 4KiB)。如果不存在映射,则会触发页面错误,让操作系统知道。
此时,操作系统决定接下来要做什么。它可以终止程序,可以随机生成数据(!),也可以将数据存储或从页面文件(或者交换文件) 在另一个存储设备上。但此时,硬件并不关心会发生什么——操作系统可以做随心所欲处理请求时。
因此,虚拟内存和页面文件不是本质上是相关的,但它们恰好在典型情况下齐头并进。
答案2
我们以 32 位 x86 CPU 为例,为了便于说明,我们进行了简化。为了传达概念,以下部分内容故意略有不准确。
允许您加载和存储内存的指令将采用 32 位参数。因此您有一个“32 位地址”空间。这意味着您可以“与”4GB 大小的 RAM 或那里碰巧有的其他任何东西“对话”。
虚拟内存让我们可以将一个地址(逻辑或虚拟地址)映射到另一个地址(物理、实际地址)。默认状态是“身份映射”,其中每个逻辑地址都设置为其虚拟地址。映射发生在 4KB“页面”级别。
您有 2 个执行级别 - 用户模式和内核模式。内核模式需要进行身份映射,因为它管理系统和其他进程。
在用户模式下,内核映射内存,其中 RAM 从地址 0 开始,并且只能达到分配给它的内存量。内核控制所有进程的内存映射,并管理哪些内存是空闲的和正在使用的。内核可以从任何地方挑选空闲的 4K 字节页面并排列它们,使它们在用户模式进程看来是连续的。
如果用户模式页面访问的地址包含无效页面,则映射机制可能会导致“页面错误”。如果用户模式应用程序尝试访问比其拥有的更多的内存,它将访问“坏”页面并引发内核异常。然后内核会以“分段错误”错误将其杀死。内核 API 允许应用程序请求更多内存 - 然后内核会尽可能地将一些可用内存映射到该应用程序,并在完成后释放它。
因此,虽然您拥有 32 位地址空间,但您不能在用户进程下随意使用所有地址,除非那里映射了某些内容。
现在 - 如果进程处于休眠状态,内核可能会故意将某些页面标记为“坏的”,如果它确定这些页面已经有一段时间没有被访问过,并将它们写入磁盘。当进程唤醒时,它将尝试访问这些坏的页面并触发内核异常。内核不会“分段错误”,而是会从磁盘检索页面,将它们重新放入内存中(可能在不同的物理位置,但映射到进程的相同逻辑位置),然后恢复进程。这就是交换或页面文件如何融入其中。
现代 Windows 和 Linux 内核都提供了一种称为 的功能,mmap
这种机制被“故意”使用,允许像访问内存一样访问文件。用户空间进程可以选择一个地址来放置它 - 内核将通过动态加载或写入文件的正确部分来响应“故障”。它使用这种分页机制来实现这一点。在具有非常宽的地址空间的 64 位系统上,可以像访问内存中的文件一样访问非常大的文件,这简化了一些程序。