背景:
在许多情况下并不需要将整个程序放到内存中:
1 程序通常有处理异常错误条件的代码。由于这些错误即使有也很少发生,所以这种代码几乎不执行
2 数组、链表和表通常分配了比实际所需要更多的内存
3 程序的某些选项或特点可能很少使用
能够执行只有部分在内存中的程序会有很多好处:
1 程序不再受现有的物理内存空间限制。用户可以为一个巨大的虚拟地址空间写程序,简化了编程操作
2 因为每个用户程序使用了更少的物理内存,所以更多的程序可以同时执行。CPU使用率也增加,而响应时间或周转时间并不增加
3 由于装入或交换每个用户程序到内存中所需的I/O会更少,用户程序会运行得更快。
因此,运行一个部分在内存中的程序不但有利于系统也有利于用户。
虚拟内存将用户逻辑内存与物理内存分开。
虚拟内存通常采用请求页面调度来实现。请求分段调度也可用来实现虚拟内存。
请求页面调度:
请求页面调度系统类似于分页系统加上交换。进程驻留在次级存储器上(通常为磁盘),当需要执行进程时,使用懒交换(lazy swapper),只有在需要页时,才将它调入内存。
交换程序对整个进程进行操作,而调页程序只是对进程的单个页进行操作,因此,在讨论有关请求页面调度时,需要使用调页程序而不是交换程序。
基本概念:
当换入进程时,调页程序推测在该进程再次换出之前会用到哪些页。把必须的页调入内存。
对这种方案,需要一定形式的硬件支持来区分哪些页在内存里,哪些页在磁盘上。有效-无效位可以用于这一目的。
有效:表示相关的页既合法也在内存中
无效:不在进程的逻辑地址空间内或者有效但是在磁盘上
对于调入内存的页,其页表条目的设置与平常一样。
对于不在内存的页,其页表条目设置为无效,或包含该页在磁盘上的地址。
当进程试图访问那些尚未调入到内存的页时,对标记为无效的访问会产生页错误陷阱。
分页硬件,在通过页表转换地址时,会发现已设置了无效位,会陷入操作系统。这种陷阱是由于操作系统未能将所需的页调入内存,而不是由于试图使用非法内存地址而引起的无效地址错误。处理这种页错误的程序比较简单:
1 检查进程的页表(通常与PCB一起保存),以确定该引用是合法还是非法的地址访问。
2 如果引用非法,那么终止进程。如果引用有效但是尚未调入页面,那么现在应调入
3 找到一个空闲帧
4 调度一个磁盘操作,以便将所需要的页调入刚分配的帧
5 当磁盘读操作完成后,修改进程的内部表和页表,以表示该页已在内存中
6 重新开始因非法地址陷阱而中断的指令。进程现在能访问所需的页,就好像它似乎总在内存中。
一种极端情况是所有的页都不在内存中,这时就开始执行进程。这种方案称为纯粹请求页面调度:只有在需要时才将页调入内存。
有的程序单个指令可能访问多个页地内存,可能产生多个页错误。这种情况会产生令人无法接受的系统性能。幸运的是,这种情况极为少见。程序具有引用的局部性,这使得请求页面调度性能较为合理。
支持请求页面调度的硬件与分页和交换的硬件一样:
1 页表:该表能够通过有效-无效位或保护位的特定值,将条目设为无效
2 次级存储器:该次级存储器用来保护不在内存中的页。
对于一些特殊的错误,有一些方法能完善系统:
1 微码计算并试图访问两块地两端,在修改之前就知道没有页错误,才可以执行移动
2 使用临时寄存器来保护重写位置的值。
请求页面调度的性能
对于请求页面调度,降低页错误率是非常重要的。否则,无效访问时间会增加,会显著地降低 进程执行。
进程创建:
写时复制(copy-on-write):
这种方法允许父进程与子进程开始时共享同一页面。这些页面标记为写时复制。如果任何一个进程需要对页进行写操作,那么就创建一个共享页的拷贝。
采用写时复制技术,很显然只有被进程所修改的页才会复制,所有非修改页可为父进程和子进程所共享。
注意只有可能修改的页才需要标记为写时复制。
当确定一个页要采用写时复制时,从哪里分配空闲页是很重要的,许多操作系统为这类请求提供了空闲缓冲池。
操作系统通常采用按需填零的技术以分配这些页:在需要分配之前先填零,因此清除了以前的页内容。
内存映射文件:
虚拟内存技术来将文件I/O作为普通内存访问,这称为文件的内存映射,允许一部分虚拟内存与文件逻辑相关联。
页面置换:
基本方法:
如果没有空闲帧,那么就查找当前不在使用的帧,并使之空闲,这样来释放一个帧,将其内容写到交换空间,并改变页表表示该页不在内存中。然后就使用空闲帧来保存进程出错的帧。修改页错误处理程序以包括页置换:
1 查找所需页在磁盘上的位置
2 查找一空闲帧
a 如果有空闲帧,那么就使用它
b 如果没有空闲帧,那么就使用页置换算法以选择一个“牺牲”帧
c 将“牺牲”帧的内容写到磁盘上,改变页表和帧表
3 将所需页读入(新)空闲帧,改变页表和帧表
4 重启用户进程
FIFO页置换:
一个FIFO队列来管理内存中的所有页。
最优页置换:
置换那些在最长时间中不会被使用的页。然而最优页置换算法难于实现,因为需要引用串的未来知识。因此最优算法主要用于比较研究。
LRU页置换:
置换最长时间没有使用的页,这种方法称为最近最少使用算法。LRU置换为每个页关联该页上次使用的时间,当必须置换一页时,LRU选择最长时间没有使用的页。LRU策略经常用做页置换算法,且被认为很好,主要问题是如何实现LRU置换。可能需要大量硬件支持。
有两张方法:
1 计数器:为每个页表项关联一个使用时间域,并为CPU增加一个逻辑时钟或计数器。对每次内存引用,计数器都会增加。每次内存引用时,时钟寄存器的内容会复制到相应页所对应页表项的使用时间域内。置换具有最小时间的页,这种方案需要搜索页表以查找LRU页,且每次内存访问都要写入内存。在页表改变时也必须要保证时间,必须考虑时钟溢出。
2 堆栈:实现LRU置换的另一个方法是采用页码堆栈。每当引用一个页,该页就从堆栈中删除并放在顶部,这样,堆栈底部总是LRU页,该堆栈可实现为具有头指针和尾指针的双向链表
每次内存引用都必须更新时钟域或堆栈,如果每次引用都采用中断,以允许软件更新这些数据结构,那么它会使内存引用慢至少10倍
LRU近似页置换:
很少有计算机系统能提供足够的硬件来支持真正LRU页置换算法。有的系统不提供任何支持,因此必须使用其他置换算法(如FIFO算法)。然而很多系统都通过引用位方式提供一定的支持。页表内的每项都关联着一个引用位。每当引用一个页时(无论读或写),相应页的引用位就被硬件置位。
开始,操作系统会将所有引用位都清零。随着用户进程的执行,与引用页相关联的引用位被硬件置位。通过检查引用位,能确定那些用过而那些没用过。这种部分排序信息导致了许多近似LRU算法的页置换算法。
1 附加引用位算法:
可以为位于内存中的每个表中的页保留一个8bit的字节。操作系统把每个页的引用位转移到其8bit字节的高位,而将其他位右移,并抛弃最低位。如果将8bit字节作为无符号整数,那么具有最小值的页为LRU页,且可以被置换。
2 二次机会算法:
二次机会置换的基本算法是FIFO置换算法。当要选择一个页时,检查其引用位。如果其值为0,那么就直接置换该页。如果引用位为1,那么就给该页第二次机会,并选择下一个FIFO页。当一个页获得第二次机会时,其引用位清零。且其到达时间设为当前时间。因此获得第二次机会的页,在所有其他页置换之前,是不会被置换的。另外,如果一个页经常使用以致于其引用位总是得到设置,那么它就不会被置换。
一种实现二次机会算法的方法是采用循环队列。用一个指针表示下次要置换哪个页。当需要一个帧时,指针向前移动直到找到一个引用位为0的页。在向前移动时,它将清除引用位。
3 增强型二次机会算法
通过将引用位和修改位作为一个有序对来考虑,能增强二次机会算法。有下面四种可能类型:
1 (0,0)最近没有使用且也没有修改。---用于置换的最佳页
2 (0,1)最近没有使用但修改过。---不是很好,因为在置换之前需要将页写出到磁盘
3 (1,0)最近使用过但没有修改---它有可能很快又要被使用
4 (1,1)最近使用过且修改过---它有可能很快又要被使用,且置换之前需要将页写出到磁盘
当页需要置换时,每个页都属于这四种类型之一。置换在最低非空类型中所碰到的页,可能要多次搜索整个循环队列。
基于计数的页置换:
1 最不经常使用页置换算法:要求置换计数最小的页。
2 最常使用页置换算法:
这两种算法的实现都很费时,且不能很好地近似OPT置换算法。
页缓冲算法:
系统通常保留一个空闲帧缓冲池。当出现页错误时,会像以前一样选择一个牺牲帧,在牺牲帧写出之前,所需要的页就从缓冲池中读到空闲内存。
帧分配:
帧的最小数量:
所分配的帧不能超过可用帧的数量。也必须分配至少最少数量的帧。
分配算法:
全局分配与局部分配:
全局置换:允许一个进程从所有帧集合中选择一个置取帧,而不管该帧是否已分配给其他进程;一个进程可以从另一个进程中取帧。
局部置换:要求每个进程仅从其自己的分配帧中进行选择。
全局置换通常会有更好的系统吞吐量,且更为常用。
系统颠簸:
频繁的页调度的行为称做颠簸。如果一个进程在换页上用的时间要多于执行时间,那么这个进程就在颠簸。
系统颠簸的原因:
操作系统监视CPU的利用率,如果太低,引入新进程,新进程获得帧,其他进程页错误增加,排队等待换页设备,CPU利用率降低,操作系统引入新进程。
工作集合模型:
工作集合模型是基于局部的假设。该模型使用参数△定义工作集合窗口。其思想是检查最近△个页的引用,这最近△个引用的页集合称为工作集合。如果一个页正在使用中,那么它就在工作集合内,因此,工作集合是程序局部的近似。
工作集合精确度与△的选择有关。
工作集合模型的使用较为简单,操作系统跟踪每个进程的工作集合,并为进程分配大于其工作集合的帧数。
页错误频率:
为所期望的页错误率设置上限和下限,如果实际页错误率超过上限,那么为进程分配更多帧,如果实际页错误率低于下限,那么可从该进程中移走帧。
操作系统样例
其他考虑:
预约式页面调度
同时将所需的所有页一起调入内存中。
页大小:
TLB范围:
反向页表:
程序结构:
I/O互锁:
实时处理: