今天几乎所有内核都使用 MMU 提供的虚拟内存。他们使用全局页表(其地址位于 CPU 寄存器中)和页到进程的页管理器/映射器来实现这一点。vmlinuz
例如,中的“vm”表示 linux 内核支持虚拟内存。
所有这一切都是可能的,因为 MMU 将连续的内存地址映射到 x86 架构能够理解的内存段。
最初的 UNIX 内核确实有一个vmunix
版本,我相信它一定使用了类似的技术。然而,最初的 UNIX 内核是在 MMU 可用之前编写的。如果我没有记错的话,最初的 UNIX 内核(简称unix
)是在 x86 体系结构存在之前编写的。从历史上看,它确实在 PDP-9 和 PDP-11 上运行。
该内核如何执行内存寻址和管理?它是基于段的寻址(两个数字)还是全内存寻址(单个数字)?它如何在处理之间分离内存?
虚拟内存比 Unix 早了将近十年:1961年的Burroughs B5000中就有一个虚拟内存。它没有现代意义上的 MMU(即基于页面),但提供了相同的基本功能。1965 年的IBM System/360 Model 67(仍然比 Unix 更老)有一个 MMU。Intel x86 处理器直到 1986 年的 80386 才获得 MMU。
实现 Unix 系统实际上并不需要 MMU。它确实需要某种形式的虚拟内存,否则实现fork
系统调用将非常困难。fork
通过复制现有进程来创建进程的系统调用自第一个版本以来就是 Unix 的基本部分,因此它确实需要虚拟内存。参见DM Ritchie 和 K. Thompson,UNIX 分时系统,CACM,1974 年,§V“进程和图像”。
我不知道运行第一个 Unix 版本的硬件的详细信息,但它们确实具有分段体系结构形式的虚拟内存。CPU 在程序取消引用的指针(虚拟地址)和内存中的实际位置(物理地址)之间进行转换。映射是通过向虚拟地址添加偏移量来执行的。在进程之间的每次上下文切换时,都会调整包含偏移量的寄存器。
尽管几乎所有的 Unix 实现都提供了进程隔离,但在没有内存保护的硬件上的一些历史实现并不是这种情况(在 1970 年代,以及在 8088 和 80286上的MINIX的 1980 年代)。内存保护与地址虚拟化有些正交;MMU 提供两者,简单的分段架构不提供,MPU¹ 提供保护而无需虚拟化。对于没有 MMU 的系统,有一个 Linux 实现,即uCLinux,但由于缺少fork
许多程序无法运行(唯一支持的fork
是vfork
它需要execve
在之后立即调用子进程)。
¹ MPU(内存保护单元)记录了每一页内存的访问权限。