虚存子系统是所有 UNIX 系统的核心组件。下面讨论虚存系统的实现及其对操作系统中几乎其他所有子系统的作用和影响。首先详细说明一些基本的内存管理问题;然后具体分析 Linux 操作系统如何实施虚存管理任务。进程(也标记为任务或默认线程)通过虚存子系统能够查看地址空间中的线性字节范围,这个功能与物理内存中的物理布局或者分片情况无关。 线程可以在一个呈现为 CPU 全部地址空间的虚拟环境中执行。这种(支撑)执行框架为进程提供了一种大型编程模型。在这种情形下,作为地址空间的内存虚拟视图被呈现给应用,而虚存子系统透明地管理虚拟存储器基础架构,从而对物理内存子系统以及辅助存储器加以一致管理 。

内核映像部分也称为标识映射段,而内核模块部分经常称为页表映射段。对高端地址空间(0xFFFF ..)的访问机制与平台相关。在 32位系统上,每个进程的虚址空间为 4GB;而在 64 位系统上,每个进程在理论上的虚址空间大小2^64通常并未全部利用。 某些系统(实质上是真正的处理器)只允许每个进程的虚址空间大小为 2^44。

一、内存与地址空间

由于物理内存子系统的延迟低于磁盘子系统, 虚存子系统所面临的挑战之一是将访问最频繁的内存部分保持在速度更快的主存中。当物理内存短缺时, 虚存子系统需要释放出部分物理内存。这通过将较少使用的内存页面输出到备份存储器上来完成。因此,进程无需管理物理内存分配的细节,从这个意义上说, 虚存子系统提供了资源虚拟化功能。进程也无需对信息和故障的隔离加以管理,因为每个进程都在自己的地址空间中执行。大多数情况下,通过阻止进程访问其合法地址空间之外的内存, 内存管理部件中的硬件机制可以执行内存保护功能。其例外情形是在多个进程之间显式共享的内存区域。


1、地址空间

进程虚址空间的定义是作为运行环境呈现给进程的内存地址范围。在进程生命周期的任何时间点上,都会有一些进程地址被映射到物理地址,而另一些进程地址则不被映射。 当对fork()系统调用进行初始化时, 内核创建进程虚址空间的基本框架。进程内部的虚址空间布局由动态链接器建立,可以随着硬件平台的不同而变化。一般地, 虚址空间
由称为虚拟页面的同等大小的内存容量构成。在IA-32环境中,页面大小为4KB;在IA-64体系结构中, 页面大小可配置为 4KB、 8KB、 16KB或 64KB。 任何 Linux进程的虚址空间又进一步划分为两个主要区域: 用户空间和内核空间。 用户空间驻留在地址空间的较低部分,从地址零开始,其上限为在 processor.h中规定的与平台有关TASK_SIZE取值。 其余地址空间则保留给内核。 所示。由于页表假定为空的,该读操作会导致一个页面故障。为了响应这个页面故障, Linux内核会搜索该特定进程的 VM区域(area)列表, 以便定位包含该故障地址的 VM区域。在确定了针对该特定请求必须访问的页面之后, Linux发起一个磁盘文件读操作,如序号 2所示。当I/O子系统提供该文件后, 操作系统将数据复制到一个可用的页帧中,如序号3所示。完成这个读页面故障处理所需的最后步骤是对页表进行更新以便将虚址映射至包含数据的物理页帧。之后系统可以重新初始化这个读请求。此时该请求将成功完成,因为所需的数据已经可用。
                         
    诸如 kswapd或 pdflush线程等只访问内核地址空间的任务使用了一个匿名的地址空间,因此这些情况下的 mm指针引用值为 NULL。因为 mm结构包含了两个用于建立虚存环境的主要数据结构指针,所以被看作是虚存子系统核心的入口点。第一个结构是页表,第二个结构称为虚存区域。从内核的角度而言, 系统范围内的页表足以实现虚存机制。 一些更传统的大型页表, 包括分簇页表机制, 在表示大型地址空间时的效率并不高。