Skip to content
On this page

内存虚拟化

抽象:地址空间

上面我们解决了 CPU 虚拟化的问题,接下来要解决内存的虚拟化。

对内存实行像 CPU 那样的时分共享固然可行,但是太慢了,而且多个程序同时放在内存中,进程保护就变成了重要问题,人们不希望一个进程可以读取其他进程的内存,更别说修改。

所以我们要提供一个易用的物理内存抽象,这个抽象叫做地址空间,是运行的程序看到的系统中的内存,这是内存虚拟化的关键。

一个进程的地址空间包含运行程序的所有内存状态。比如:程序的代码必须在内存里,因此它们在地址空间里。当程序在运行的时候,利用栈来保存当前函数的调用信息,分配空间给局部变量、传递参数和返回值。最后,堆用于管理动态分配的、用户管理的内存,当然还有其他东西。

程序的地址空间大致是这样子:程序代码 => 堆 => 未分配 => 栈。在程序运行的时候,在顶部的堆和在底部的栈是可以变长的,所以把它们放在那里,但是栈和堆的位置只是约定,如果你愿意,你可以安排他们的位置。

程序并不在物理地址的 0~xKB 的内存中,而是可以加载在任意的内存地址,进程在访问地址0的时候实际上被定向到了其他位置,这是内存虚拟化的关键,是每个现代计算机系统的基础。

虚拟内存的目标

主要目标是透明,实现虚拟内存的方式应该让运行的程序无法察觉,程序不应该感知到自己被虚拟化了,相反,程序应该感觉自己拥有自己的私有内存,在幕后操作系统和硬件完成了所有工作,让不同的工作复用内存,从而实现这个假象。

第二个目标是效率,包括时间和空间,在实现这一点上,操作系统不得不依靠硬件支持。

第三个目标是保护,一个进程不能访问或是更改其他进程的内存,操作系统也不能受进程的影响,每个进程都应该在独立的环境中运行,避免出错或恶意进程的影响。

部分内存操作 API

在运行C程序的时候,会分配两种类型的内存,一种是栈内存,它的申请和释放由编译器隐式管理,因此有时被称为自动内存。当你从函数退出时,内存就会被释放,因此你希望有些信息长期存在于函数调用之外,这时就需要第二种类型的内存,就是堆内存。堆内存所有的操作都必须交给程序员显式的完成,因此也获得了更富于变化的用法。

malloc() 调用

malloc() 函数非常简单,传入需要申请的堆空间大小,它成功就返回一个指向新申请空间的指针,失败就返回 NULL。`malloc() 只需要一个 size_t 类型的参数,该参数表示你需要多少字节,大部分时候程序员不会传入数字,而是使用各种函数和宏,比如:

cpp
double *d = (double *) malloc(sizeof(double))

free() 调用

事实证明,分配内存是简单部分,知道何时以及是否是否释放内存是困难的部分,但是释放内存的 API 也是同样简洁的。

cpp
free(d)

仅传入 malloc() 分配的指针就行,不需要传入分配区域的大小,释放的大小由内存分配库本身记录追踪。

机制:地址转换

在实现 CPU 虚拟化的时候,我们遵循的一般准则被称为受限直接访问,原则很简单,让程序运行的时候直接访问硬件,只在一些关键点由操作系统介入,来确保在“正常的时间、地点下做正确的事情”。操作系统应该尽量让程序自动运行,同时通过在关键点的及时介入,来保持对硬件的控制。高效和控制是现代操作系统的两个主要目标。在实现虚拟内存的时候,也应该实现高效和控制的同时,提供期望的虚拟化。高效决定了我们需要硬件的支持,控制意味着操作系统要确保应用只能访问自己的内存空间。

因此我们利用一种通用技术,有时被称为基于硬件的地址转换,简称为地址转换,利用地址转换,硬件每次对内存访问进行处理,都将指令中的虚拟地址转换为实际地址。

当然光靠硬件无法实现虚拟内存,因为它只是提供了底层机制来提高效率。操作系统必须在关键位置介入,设置好硬件,以便完成正确的地址转换,因此它必须管理内存,记录被占用的和闲置的内存位置,并明智而谨慎的介入,保持对内存使用的控制。

所有的工作都是为了创造美丽的假象:每个程序都有私有的内存,存放着自己的代码和数据。背后是丑陋的现实,许多程序其实是在同一时间共享着内存。通过虚拟化,将丑陋的机器显式转化为有用、强大、易于使用的抽象。

在二十世纪五十年代后期,基于硬件的地址转换第一次出现,在那时只是一个简单的思想,称为基址加界限机制(base and bound),又叫动态重定位。具体来说,每个 CPU 需要两个硬件寄存器:基址寄存器和界限寄存器。这组寄存器让我们能把地址空间放在物理内存的任何位置,同时确保进程只能访问自己的地址空间。

在程序实际运行的时候,操作系统会决定其在物理内存中的实际加载地址,并把其实地址记录在基址寄存器中。当进程运行时,进程产生的所有内存引用都按照 物理地址=虚拟地址+基址 的公式,被转换为物理地址。

Released under the MIT License.