虚拟存储器出现的背景
在没有虚拟存储器的时代,由于系统里面的所有进程都要共享主存,同时又因为主存资源是有限的,而所有进程的所占用的空间远大于主存空间的大小,这就导致出现了两个问题:1、会有进程因为主存被其它进程使用完,而导致某些进程因为使用不到主存空间而停下来。2、进程与进程之间对主存中数据的操作没有进行隔离,导致一个进程可能操作到另外一个进程的数据。为了解决这两种情况,现代计算机系统中出现了虚拟存储器。
虚拟存储器的概念
虚拟存储器是对主存的抽象,虚拟存储器主要提供了三个方面的重要能力:1、虚拟存储器将主存看做是磁盘的高速缓存,根据CPU取数据的需求,在主存和磁盘之间来回的传递数据,主存中只存放使用频率比较高的数据,高效地使用了主存。2、为每一个进程提供了一个一致的地址空间,简化了存储器的管理。3、它保护了每个进程的地址不被其它进程破坏。同时,虚拟存储器是硬件异常(缺页时会出现硬件异常,系统内核接收到硬件异常后会重新将所缺的页从硬盘换到内存中,然后再重新触发导致缺页异常出现的那条读取数据的指令,重新读取数据)、硬件地址翻译(由于CPU中的ALU单元计算出的是虚拟地址,而不是内存单元的物理地址,这就要求有一个硬件能将从虚拟地址计算出物理地址,这个地址翻译的功能就是由集成到CPU芯片中的MMU完成的)、主存、磁盘文件和内核软件之间的完美交互完成的。通过这几部分的完美交互,为每个进程提供了一个一致的、私有的地址空间。
寻址方式
了解虚拟存储器要从计算机的寻址方式开始说起,早期的计算机的寻址方式是物理寻址,所谓的物理寻址就是CPU直接计算出数据所在内存单元的物理地址,然后将物理地址交地址总线,地址总线将地址传输到物理存储器,物理存储器根据地址总线传输过来的物理地址去相应的物理存储器单元提取数据,然后将数据通过数据总线回传给CPU,CPU将数据在放入相应的寄存器。早期的物理寻址如下图所示:
而现代的计算机系统使用的是虚拟寻址,其寻址模型和上图描述的物理寻址模型是一样的,只是这个时候由ALU单元计算出的地址不是数据存放物理存储器的物理地址而是一个虚拟地址,虚拟地址会被送到一个被称作MMU的硬件单元进行虚拟地址到物理地址的转换,转换成真实的物理地址之后,后续操作和物理 寻址的后续操作是一样的,其寻址模型如下:
有个地方需要特别说明一下,MMU通过虚拟地址计算物理地址是通过查表计算的,而这个虚拟地址与物理地址对应的记录是存放在内存单元中的一张二维表中的,这个表是由操作系统维护的。
虚拟存储器是如何进行数据存取的
上面讲到了虚拟存储器的寻址方式,接下来就要讲一下虚拟存储器是如何进行数据存取的。首先虚拟存储器是存放在硬盘上的一个数组集合,数组集合中的每个单元都是指向硬盘上存放数据的单元的索引,而每个数组单元除了有索引之外,还存放有当前索引所指向数据的状态,这些状态将虚拟存储器数组分为了三个不相交的集合:1、未分配的单元(虚拟存储器未进行存储单元分配,该单元中没有任何值)。2、已分配单元,但未缓存到主存中(记录磁盘上已经分配使用了的存储单元,但是该单元中存放的数据未存放到主存中数据单元的索引)。3、已分配,已缓存单元(记录数据缓存到主存单元的物理地址)。虚拟存储器和物理存储单元的关系如下图所示:
上图中,虚拟存储器中的0,4,7号单元中记录的是主存数据存储单元的地址,而1,3,6记录的是磁盘上已分配但未被缓存到主存中的数据所在存储单元的磁盘物理地址,2,5号单元则是空的没有任何数据。还有一点需要特殊说明的是,由于数据在磁盘上的最小存储单元为块,所以数据在磁盘和主存之间传输时是传输的块大小的整数倍,为了和计算机数据传输的大小相吻合,虚拟存储器将每个最小传输单元称为页,页单元为块单元的整数倍。
页表
由于现代操作系统的地址翻译都是将虚拟地址翻译为物理地址,之前在介绍虚拟存储器的寻址方式的时候说过MMU将虚拟地址翻译为物理地址是通过查表的方式实现的,而这张表就是页表,这是由操作系统维护的,是连接虚拟存储器和物理存储器的一张非常关键的表。首先介绍下页表的结构。页表是存放在内存中的,其存在也是一张二维表,表中的维度为有效位和地址(分为主存的物理页号和磁盘块地址),表中的每条记录称为页表条目。有效位表示当前虚拟页是否被缓存在了内存中,如果当前有效位表示数据对象被缓存,则此条数据的地址位表示数据所在主存单元的物理页号,如果当前有效位表示数据对象未被缓存,则次条记录的地址位表示数据在虚拟存储器单元的地址。页表、虚拟存储器、物理存储器三者的关系如下:
由上图可以看出,页表中的非未分配页其地址位都是指向某个特定的虚拟页,其指向的优先级为:1、如果缓存,则指向内存单元,2、如果未缓存,则指向虚拟存储器。某条页表记录,其指向的地址中的数据是永远都不会改变的。
关于页命中与缺页
所谓页命中即MMU通过页表查找数据时,如果在页表中查找到的数据的标志位为1,则表示此页命中,如果在页表中查找到的数据标志位为0时,则表示这条记录对应的虚拟页未放入进物理存储器中,此时会触发一个缺页异常,操作系统会捕捉到这个异常,然后通过算法(应该是最长时间未被访问的页算法)在物理存储器中选中一个换出页,将其中的数据写入到对应的虚拟存储器中,然后在将页表所指向的虚拟存储器中的对应页换入到之前被换出的页当中,当页换入主存之后,操作系统会将页表中对应记录的标志位和地址位修改为正确的状态,紧接着会重试引发缺页异常之前的指令,这个时候再去访问对应的数据就是页命中了。
关于虚拟存储器是如何对进程对数据的访问进行隔离的
虚拟存储器为所有进程都提供了一个相同的虚拟存储器空间,而现代的操作系统又为每个进程提供了一张独立的页表,通过以上两种措施就可以保证每个进程只存取自己进程所使用的数据,而不会误读或者误写到其它进程的数据。
关于MMU是如何进行地址翻译的
由ALU计算出的虚拟地址分为两个部分:1、虚拟页号,也就是页表中记录的索引。2、虚拟页号偏移量,也就是在基址基础上便宜的量,关于MMU如何进行地址计算的模型如下:
首先由ALU计算出虚拟地址,然后MMU将取到的虚拟页号和页表基址寄存器中存放的页表基址相加得到虚拟页所在页表中的存放单元,然后查看对应数据单元的有效位,如果有效位为1,则取地址位的地址加上虚拟页偏移量得到数据所在主存中的物理单元地址,这样就可以将数据正确的取出。如果有效位为0则并且地址位中有数据,则进行缺页处理流程,如果有效位为0,同时地址位的数据为NULL,则不进行处理,因为当前虚拟存储单元未被分配。