虚拟内存的基本出发点

理想中的存储器是更大,更快,更便宜的非易失性存储器。硬盘的容量很大,但是速度很快,所以可不可以把硬盘的容量用上,甚至把磁带用上。把不常用的数据放在硬盘上,把常用的数据放在内存中,使得在有限的内存中放的是经常访问的数据。这样就有了一种虚拟的大内存的感觉,所以叫做虚拟内存。
虚拟内存=物理内存+硬盘

虚拟内存的技术

(1)覆盖技术

目标:是在较小的可用内存中运行较大的程序,常用于多道程序系统,与分区存储管理配合使用。
基本原理:把程序按照自身的逻辑结构,划分为若干个功能上相对独立的程序模块,那些不会同时执行的,模块可以共享一块内存区域,按照时间的先后顺序来执行。必要部分的代码和数据常驻内存,可选部分在其他程序模块中实现,平时放在外存,只有在需要用到的时候才装入内存。不存在调用关系的模块不必同时装入内存,从而可以实现相互覆盖,即这些模块共用一个分区。简单的理解就是分时的方法。
问题:对程序员的要求比较高,需要程序员来管理,对程序员不透明。

(2)交换技术

早期UNIX操作系统采用的方式,由操作系统来管理,而不是程序员来管理。操作系统来决定哪些在内存,哪些在硬盘。对程序员来说,交换是透明的。
目标:多道程序在内存中时,可以让正在运行的程序或者是需要运行的程序获得更多的内存资源。
方法:操作系统把一个进程的程序送到外存,从而获得空闲的内存空间,这被称为换出。将外存中的某个进程的地址空间读入到内存中,叫做换入。换入和换出内容的大小是整个程序的地址空间。
需要考虑的问题:1)何时发生交换,不能频繁的换入换出。2)交换区的大小,必须足够大以存放所有用户进程的所有内存映像的拷贝。3)程序换入的时候,可能换入的位置不再是之前换出的位置了,此时怎么进行地址的重定位。(可以使用动态的地址映射)
问题:一次是一个程序的交换的粒度,会导致系统开销比较大。很多时候不需要换出整个程序,而是只需要换出程序的一部分。

页面置换算法

(1)功能

当缺页中断发生后,需要调入新的页面但是当前页面的内存已满时,需要选择内存中的哪个物理页面被置换出去。

(2)目标

尽可能地减少页面的换入换出的次数。

(3)几种页面置换技术

1)最优页面置换算法
基本思路:当一个缺页中断发生时,对于保存在内存中的每一个逻辑页面,计算在它的下一次访问之前还需要等待多长时间,从中选择等待时间最长的那个,作为被置换的页面。
2)先进先出算法(FIFO)
基本思路:选择在内存中驻留的时间最长的页面并且淘汰之。系统维护一个链表,记录了所有位于内存中的逻辑页面。从链表的排列顺序来看,链表首部的驻留时间最长,链表尾部的驻留时间最短。当发生一个缺页中断的时候,把链表的首部页面淘汰出去,并且把新的页面添加到链表的尾部。
问题:性能较差,调出的页面可能是经常要访问的页面。
3)最近最久未使用页面算法(LRU)
基本思路:当一个缺页中断发生时,选择最久未使用的那个页面,并淘汰它。其实是根据历史来推断未来,是对于OPT算法的一种近似。这种合理性是基于程序的时间和空间局部性。
实现:第一种方法是系统维护一个页面链表,最近刚刚使用过的页面是作为首结点,最久未使用的页面是作为尾结点。每次访问内存时,找到相应的页面,把它从链表中摘下来,移动到链表的首部;如果发生缺页中断,则把链表末尾的页面给淘汰掉。
第二种方法是设置一个活动页面栈,当访问到某页时,将此页号压入到栈顶,然后考察栈内是否有与此页面相同的页号,如果有就抽出。当需要淘汰一个页面时,总是选择栈底的页面,因为它是最久未被使用的。
问题:这两张方法的开销都很大,因为每次都要访问链表或者是栈。
4)最不常用算法(LFU)
基本思路:当一个缺页中断发生时,选择访问次数最少的那个页面并淘汰之。
实现方法:对每个页面都设置一个访问的计数器,每当一个页面被访问的时候,该页面的访问计数器就会加1,而在发生缺页中断的时候,会淘汰计数值最小的那个页面。
问题:一个页面在进程中刚开始的时候使用的很多,但是以后就不使用了。这样就不合适使用LFU算法。