页面置换
1. 原理
页面置换:当物理内存中没有空闲帧时,查找当前没有使用的帧,将其内容写到交换空间,然后使用该帧保存出错的页。
这里需要注意的是,内存不仅仅是给用户进程使用,I/0 缓存也要使用大量的内存空间,这大大增加了内存分配算法的压力。当操作系统中没有空闲帧时,如果有进程申请空闲帧,常见的处理方法有以下两种:
- 终止用户进程;
- 交换出一个进程,释放其所有帧供其它进程使用;
终止用户进程的做法对提升 CPU 的使用率和系统吞吐量并没有好处,因此不是最佳选择,现在大部分系统都采用页置换来提升系统利用率。
2. 基本页置换
页置换基本流程:
- 查找所需页在磁盘上的位置;
- 查找空闲帧;
- 如果有空闲帧,就使用它;
- 如果没有空闲帧,使用页置换算法选择一个“牺牲”帧;
- 将“牺牲”帧的内容写到磁盘上,改变页表和帧表;
- 将所需页读入空闲帧,改变页表和帧表;
- 重启进程;
基本页置换的改进
在基本页置换中,如果系统中没有空闲帧,那么需要将一个页写出,一个页写入。这相当于要进行两次页传输,这实际上增加了页错误处理时间,同时也增加了有效访问时间。
为了提高效率,可以在每个页或帧上增加一个修改位,表示此页面是否被修改过。在页置换时,如果选中的页修改过就正常执行页置换操作,如果选中的页没有修改过,就可以直接向帧中写入页面,因为帧中的内容和磁盘上的内容时一样的,这样做可以节省一半的 I/O 时间,避免将帧中的内容重复写到磁盘上。
3. FIFO页置换
FIFO置换:算法为每个页记录着该页调入内存的时间,当必须置换一页时,选择最旧的页。
具体实现时可以创建一个FIFO队列来管理内存中的所有页。每次置换时从队首选择“牺牲”页来置换,将置换后的页加入队尾。
如上图是FIFO置换算法的引用串样例,总共出现15次页错误陷阱。
FIFO页置换算法容易理解和实现,但是性能不总是很好,会出现Belady异常。
Belady异常指的是页错误率可能随着内存中总帧数的增加而增加,即内存变大了但性能下降了。
4. 最优置换
原理:置换最长时间不会使用的页。最优置换是所有算法中产生页错误率最低的,且绝对没有Belady异常,对于给定数量的帧会产生最低可能的页错误率。
下图为最优置换的引用串样例:
在上图的页置换过程中共出现9次页错误陷阱,性能优于FIFO置换。
然而实际上,最优置换算法难以实现,因为需要引用串的未来知识,因此最优算法主要用于比较研究。
5. LRU页置换
原理:当必须置换一页时,LRU选择最长时间没有使用的页来进行置换。LRU和最优置换一样没有Belady异常。
FIFO算法和最优置换的区别在于:
- FIFO算法关注的是页调入内存的时间;
- 最优置换关注的是页将来使用的时间;
而未来页的使用情况是难以预测的,因此LRU算法关注的是页的过去使用情况,与最优置换正好相反,它将离过去最近作为不远将来的近似。
从上图可知LRU置换算法产生12次页错误陷阱,虽然比最优置换性能差些,但是优于FIFO置换算法。
实现:LRU置换算法经常最为页置换算法,在实际实现时需要一些硬件的支持。有两种常见的实现方法:
- 计数器:为每个页表项关联一个时间域,并为CPU增加一个计数器。每次引用内存时计数器都会增加,同时将计数器中的数值复制到相应页所对应的表项的时间域里。这样最长时间没有使用的页即是拥有最小时间域的页表项。
- 栈:每当引用一个页,该页就从栈中删除并放到顶部。这样栈顶总是最近使用的页,栈底总是LRU置换页。
注意:如果只有标准的TLB寄存器,而没有其他硬件支持,那么这两种LRU实现方式都是不可能的。如果使用软件来更新页表的时钟域或栈,那么回事内存引用至少慢10倍,这几乎是无法容忍的。
6. 近似LRU页置换
很少有计算机提供足够的硬件支持真正的LRU置换算法,许多系统都通过引用位的方式提供一定的支持。
每个页表项都关联着一个引用位,开始时操作系统会将所有引用位置零,每当引用一个页时,相应的引用位被硬件置位。之后通过检查引用位可以知道哪些页使用过,哪些页没有使用过。
通过引入引用位,产生了一下几种近似LRU置换算法。
6-1 附加引用位算法
原理:记录一段时间内页面的引用情况,根据页面的引用情况选择置换页。
假设在每个页中保留一个8位的字节,在规定的时间间隔(如每100ms)内,时钟定时器会产生中断,并将控制交给操作系统。操作系统把每个页的引用位转移到8位字节的高位,然后将其它位右移一位,并抛弃最低位。这样这个8位字节中包含这页面8个时钟周期内的引用情况。如00000000
表示页面在8个时钟周期内没有使用,11111111
表示页面在8个时钟周期内,每个时钟周期中至少被使用一次。
6-2 二次机会算法
原理:二次机会置换基本算法是FIFO置换算法,当要选择一个页时,检查其引用位。如果其值为0,那么直接置换;如果引用位为1,那么就给该页第二次机会,并选择下一个页。
总结起来二次机会算法就是给用过的页面一个继续使用的机会,获得机会的页在所有其它页置换之前是不会被置换的。如果一个页面经常使用以致其引用位总是被设置,那么它是不会被置换的。
6-3 增强型二次机会算法
原理:引入引用位和修改位作为有序对,这个有序对的含义如下:
- (0,0):最近没有使用且也没有修改--->用于置换的最佳页
- (0,1):最近没有使用,但是修改过--->不是很好,在置换前需要将页写出
- (1,0):最近使用过,但是没有修改--->它可能很快又要被使用
- (1,1):最近使用过,且被修改过----->它可能很快要被使用,且使用前需要将页写出
每个页都属于这四种类型之一,在置换时选择最低非空类中所碰到的页。
这种方法的优点是给那些修改过的页更高的级别,从而降低I/O数量。
7. 基于计数的页置换##
为每个页保留一个用于记录引用次数的计数器,然后置换最不经常使用的页或最常使用的页。这两种置换算法分别为最不经常使用页置换算法(LFU)和最常使用页置换算法(MFU)。
这两种算法都不常用,因为实现起来都很费时。
8. 页缓冲算法##
原理:系统保留一个空闲帧缓冲池,当出现页错误时,像以前一样选择一个“牺牲”帧,但在“牺牲”帧写出前,先在空闲帧缓冲池中申请空闲内存,并将页读到空闲内存中。当“牺牲”帧写出以后,再将“牺牲”帧的内存加入到空闲帧池。
还有另外一种改进方法,就是记住哪些页在在哪些帧中,由于当帧写到磁盘上时其内容没有改变,所以在该帧被重用之前如果需要使用原来的页,可以直接从缓冲池中取出来直接用,这时不需要I/O。
9. 应用程序与页置换算法##
虚拟内存虽然提供更大的内存空间,但是并不是所有程序都适合使用系统提供的虚拟内存。比如像数据库软件,本身提供了内存管理和I/O缓冲功能,因为它比操作系统更能理解自己的内存使用和磁盘使用。如果既使用自己的I/O缓存,还使用操作系统提供的I/O缓存,那么用于这些I/O的内存必然会加倍,性能会下降。
因此操作系统一般允许应用程序直接访问内存和磁盘而不需要通过文件系统和内存管理,这对有些程序可以达到高效的目的,但是绝大多数程序使用通用的文件系统服务会更好。