一、虚拟存储技术
背景
代码必须装入内存才能执行,但是并不是所有代码必须全部装入内存。
- 错误代码
- 不常用的函数
- 大的数据结构
程序部分装入优点
局部性原理
局部性原理:一个程序只要部分装入内存就可以运行
- 整个程序不是同一时间都要运行
1968年,Denning指出:程序在执行时将呈现出局部性规律,即在一较短的时间内,程序的执行仅局限于某个部分;相应地,它所访问的存储空间也局限于某个区域。
- 程序执行时,除了少部分的转移和过程调用外,在大多数情况下仍然顺序执行;
- 过程调用将会使程序的执行轨迹由一部分区域转至另一部分区域,过程调用的深度一般小于5。程序将会在一段时间内都局限在这些过程的范围内运行;
- 程序中存在许多循环结构,多次执行;
- 对数据结构的处理局限于很小的范围。
程序部分装入技术优点:
- 进程大小不再受到物理内存大小限制
- 每个进程需要的内存更小
- 更多进程可以并发运行
- I/O更少
虚拟存储技术
虚拟存储技术:当进程运行时,先将其一部分装入内存,另一部分暂留在磁盘,当要执行的指令或访问的数据不在内存时,由操作系统自动完成将它们从磁盘调入内存执行。
虚拟地址空间:分配给进程的虚拟内存。
虚拟地址:在虚拟内存中指令或数据的位置(可以被访问)。
虚拟内存:把内存和磁盘有机结合起来使用,得到一个容量很大的“内存”,即虚存。
虚拟内存主要作用——区分开物理内存和用户逻辑内存
只有部分运行的程序需要在内存中;
逻辑地址空间能够比物理地址空间大;
允许多个进程共享同一地址空间;
允许更有效的进程创建。
虚拟内存大于物理内存
虚拟存储器的大小由2个因素决定:
- 操作系统字长(计算机系统的寻址空间);如果是32位计算机,那么寻址空间为232,也就是4G,如果是64位计算机,那么寻址空间为264。
- 内存外存容量和
我们不能简单认为虚存大小就是内存和外存容量之和。
虚拟内存的共享库
虚拟内存也允许文件和内存通过共享页而为多个进程所共享。
- 通过将共享对象映射到虚拟地址空间,系统库可以被多个进程所共享;
- 虚拟内存允许进程共享内存
- 虚拟内存可允许在创建进程期间共享页,从而加快进程创建。
写时复制(Copy-on-write)
写时复制允许父进程和子进程在初始化时共享页面。
- 如果其中一个进程修改了一个共享页面,会产生副本;
- 更加高效;
- 应用在Windows XP,Linux等系统
vfork():fork()变形,不使用写时复制。
虚拟内存实现
虚拟内存能够通过以下手段来执行实现:
- 虚拟页式(虚拟存储技术+页式存储管理)居多
- 虚拟段式(虚拟存储技术+段式存储管理)
虚拟页式有两种方式:
- 请求分页;需要访问某个页面,如果该页面不在内存,操作系统就把这个页面调入内存。
- 预调页;使用某些算法预测将要用到的页面,预先把这些页面调入内存。
二、请求分页
虚拟页式存储管理基本思想
进程开始运行之前,不是装入全部页面,而是装入一个或零个页面;
运行之后,根据运行需要,动态装入其他页面;
当内存空间已满,而又需要装入新的页面时,则根据某种算法置换内存中的某个页面,以便装入新的页面。
请求分页(按需调页)
只有在一个页需要的时候才把它换入内存
- 需要很少的I/O
- 需要很少的内存
- 快速响应
- 支持多用户
类似交换技术,粒度不同
进程驻留在磁盘上,需要执行进程时,将它换入内存。
懒惰交换:只有在需要页时,才把它调入内存。
- 交换程序对整个进程进行操作;
- 调页程序只是对进程的单个页进行操作。
有效-无效位
现在当该位设置为“有效”时,表示相关的页合法且在内存中;当该位设置为“无效”时,有两种情况:
- 一种表示相关的页为无效,也就是不在进程的逻辑地址空间内;
- 另一种表示页面有效,但是不在内存,而在磁盘上。
每一个页表的表项有一个有效-无效位相关联:
1表示在内存,0表示不在内存;
在所有的表项中,这个位被初始化为0.
缺页中断(页错误)
当进程试图访问那些尚未调入内存的页时,对标记为无效的访问,会产生缺页中断,也称为页错误陷阱。
如果对一个页的访问,首次访问该页需要陷入OS->缺页中断
- 访问指令或数据
- 查看另一个表来决定:
- 无效引用->终止
- 仅仅不在内存
- 找到页在后备存储上的位置
- 得到空的页框,把页换入页框
- 重新设置页表,把有效位设为v
- 重启指令
请求分页讨论
极端情况:进程执行第一行代码时,内存内没有任何代码和数据
- 进程创建时,没有为进程分配内存,仅建立PCB
- 导致缺页中断
- 纯请求分页
一条指令可能导致多次缺页(涉及多个页面)
如下图中的指令,copy A to B将数据块A复制到数据块B,数据块A,数据块B都跨越2个页面,因此完成这条指令需要访问6个页面,也就是需要发生6次缺页中断。这种情况令人难以接受。
幸运的是,对运行进程的分析,说明了这种情况极为少见,因为程序具有局部性(locality of reference),这使得请求调页性能较为合理。
请求分页需要硬件支持
- 带有效无效位的页表
- 交换空间(用于保存在不同内存中的页的快速磁盘空间)
- 指令重启
请求分页的性能
缺页率:0≤ p ≤ 1.0
- 如果p=0,没有缺页
- 如果p=1,每次访问都缺页
有效访问时间(EAT)
EAT=(1-p)x 内存访问时间 + p x 页错误时间
页错误时间=处理缺页中断 + [页交换出去时间] + 读入页时间 + 重启进程开销
一个请求分页的例子
存取内存的时间=200(ns)
平均缺页处理时间=8(ms)
EAT =(1-p)x 200ns+p x(8ms)
=(1-p)x 200 + p x 8000000
=200+p x 7999800
如果每1000次访问中有一个页错误,那么EAT=8.2 us
这是导致计算机速度放慢40倍的影响因子!
请求分页性能优化
页面转换时采用交换空间,而不是文件系统
交换区的块大,比文件系统服务快速;
在进程装载时,把整个进程拷贝到交换区
- 基于交换区调页
- 早期的BSD Unix
利用文件系统进行交换
- Solaris和当前的BSD
- 部分内容仍旧需要交换区(堆栈等)
三、页面置换
需要页置换的情况
一个用户进程在执行时发生缺页中断,操作系统可能会发现当前内存中没有空闲帧了,所有的内存都在使用。
如果没有空闲帧怎么办?
解决方法:
- 终止进程;
- 交换进程;
- 页面置换,又称页置换、页淘汰;
页面置换的基本方法
进程运行过程中,如果发生缺页中断,而此时内存中没有空闲的物理块,为了能够把所缺的页面装入内存,系统必须从内存中选择一页调出到磁盘的交换区。但此时应该把那个页面换出,换出时,将其内容写到交换空间,并修改页表以表示该页不在内存,这需要根据一定的页面置换算法来确定。
- 查找所需页在磁盘上的位置
- 查找一空闲页框
■ 如果有空闲页框,就使用它
■ 如果没有空闲页框,使用页置换算法选择一个“牺牲”页框
■ 将“牺牲”帧的内容写到磁盘上,更新页表和帧表 - 将所需页读入(新)空闲页框,更新页表和帧表
- 重启用户进程
页置换讨论
- 如果发生页置换,则缺页处理时间加倍
- 使用修改位modify bit或脏位(dirty bit)来防止页面转移过多——只有被修改的页面才写入磁盘
- 页置换完善了逻辑内存和物理内存的划分——在一个较小的物理内存基础之上可以提供一个大的虚拟内存
页置换算法
-
找出一个导致最小缺页率的算法
-
通过运行一个内存访问的特殊序列(访问序列),计算这个序列的缺页次数
-
访问序列是
1,2,3,4,1,2,5,1,2,3,4,5 -
最优置换置换算法(OPT)
-
先进先出置换算法(FIFO)
-
最近最少使用置换算法(LRU)
-
近似LRU算法
二次机会法
要求:
- 掌握设计思想、算法应用
- 了解部分算法的实现
先进先出(FIFO)算法
- 置换在内存中驻留时间最长的页面,也就是先进入内存的页面先被淘汰出去
- 容易理解和实现、但性能不总是很好。所淘汰的页面可能是很久以前使用的,已经不再使用的一些模块,但也可能是包含了一个以前初始化的并且不断使用的常用变量。
- 实现:使用FIFO队列管理内存中的所有页,队列中的首页将被置换,需要调入页时,将它加入队列的尾部。
现有如上图的内存访问序列,假设可用页框数量为3,初始时为空,这样开始的3个引用会引起缺页中断,并将这几页调入到空闲页框中,下一个引用2将置换7,因为7是最早进入内存的,再下一个0已存在内存,将不会产生缺页中断。上图表示出所有的缺页中断情况,共15次缺页中断。
Belady异常
引用串:1,2,3,4,1,2,5,1,2,3,4,5
- 分配3个页框,发生9次缺页
- 分配64个页框,发生10次缺页
FIFO算法可能会产生Belady异常
这张图显示了缺页次数和页框数的关系,该曲线不是一个光滑的下降曲线,这与前面所说的分配页框越多,缺页数越少相违背,这被称为Belady异常。
有的时候,分配更多的页框可能会导致更多的缺页。
最优置换算法OPT
被置换的页是将来不再需要的或最远的将来才会被使用的页。这种算法能够得到所有的算法中最少的缺页次数,也没有Belady异常。
实现?
由于需要访问序列中未来的知识,才能判断将来不再需要的页,所以该算法无法实现。
作用:作为一种标准来衡量其它算法的性能。算法结果越靠近OPT算法的结果,该算法的性能越好。
在上面的例子,使用最优置换算法会产生9次缺页。
最近最少使用算法(LRU)
置换最长时间没有使用的页,该算法最常用,性能接近OPT。基于的思想是在最近的过去很久未使用的在最近的将来也不会使用。
如下图所示,针对前面的访问序列,LRU算法将产生12次缺页。
实现:计数器(时间戳)或栈
=>开销大、需要硬件支持
LRU近似算法
在没有硬件支持的系统中,可使用LRU近似算法;
引用位
- 每个页都与一个位相关联,初始值为0
- 当页访问时设为1
三种基于引用位的算法:
附加引用位算法、二次机会算法、增强型二次机会算法
附加引用位算法(近似LRU算法)
基本思想:
- 为内存中的每个页设置一个8位字节;
- 在规定时间间隔内,把每个页的引用位转移到8位字节的高位,将其他位向右移一位,并舍弃最低位;
- 具有最小值的页为最近很少使用的页,被淘汰。
注意:帧和页框、引用位和访问位的混用!
NFU
NFU(Not Frequently Used,不经常使用)算法:
- 需要一个初值为0的软件计数器与每页相联
- 每次时钟中断时,操作系统扫描内存中的所有页面,将每页的R位(其值为0或1)加到其计数器上
- 缺页时淘汰计数器值最小的页
实质:跟踪每页被访问的频繁程度
老化算法
NFU算法修改:
- 先将计数器右移一位
- 把R位加到计数器的最左端——称为老化(aging)算法,很好地模拟了LRU
二次机会算法
需要访问位
如果访问位为0,直接置换如果将要交换的页访问位是1,则:
- 把访问位设位0.
- 把页留在内存中
- 以同样的规则,替换下一个页
实现:时钟置换(顺时针方式),即采用循环队列,用一个指针指向下次要置换的页。
FIFO的增强算法如下图:
页面置换算法小结
- OPT最优页面置换算法(操作系统不可能实现)
- FIFO先进先出页面置换算法:采取队列方式,发生缺页中断时,置换表头的页面。
- 二次机会页面置换算法:对FIFO的修改,如果表头的R位是0,则置换,若为1,则将R清零,并放回表尾。
- LRU最近最少使用算法:在缺页中断发生时,置换最近最长时间未使用的页面,实现代价很高。
- NFU最不常用算法:每个页面与一个软件计数器相关联,每次发生时钟中断,将每个页面的R位加到计数器上。
- 老化算法:修改NFU,变成老化算法可以很好的模拟LRU。每次记录R位时,先将计数器右移,然后把R的值加到最高位。发生缺页中断时,将置换计数器值最小的页面。有两点区别:1.无法区分一个时钟滴答中页面访问的先后顺序。2.老化算法的计数器位数是有限的,限制了对以往页面的记录。
- NRU最近未使用页面置换算法:访问位R,修改位M,初始值设置为0,R位被定期清零。
- 工作集页面置换算法:发生缺页中断时,淘汰一个不在工作集中的页面。工作集是最近k次内存访问所使用过的页面的集合。但是计算出工作集并不容易,常见的方法是用一定时间内内存访问的页面的集合作为工作集的近似。需要记录上次访问时间。
- WSClock工作集时钟页面置换算法 :与时钟算法有点类似,把所有页面保存在环形链表中。发生缺页中断时,首先检查指针指向的页面,若为1,则将R位清零,并把指针前移一个位置。如果R位是0,则计算生存时间,并与t比较,若大于t且页面是干净的(在磁盘上有副本),则淘汰页面,否则指针前移。
- PFF缺页中断率算法:计算每秒的缺页中断数,调整分配集(给进程在内存中分配多少页框)的大小。
下面是几道练习题:
1.一个进程分配得到4个页框,装入时间和上次访问时间(和当前时间的间隔)如下表。请问LRU算法将置换的页面存放在第()页框中。
A.3 B.2 C.0 D.1
A
2.一个进程分配得到4个页框,装入时间和上次访问时间如下表。请问FIFO算法将置换的页面存放在第()页框中。
A.3 B.1 C.0 D.2
A
1、F1FO置换算法选择最先进入内存的页面进行替换。
2、LRU置换算法选择最近最长时间未使用的页面进行替换。
3.考虑下图中的页面序列。假设从页面B到页面A的R位分别是11011011。 使用第二次机会算法,被移走的是页面()。
A.C B.D C.A D.B
B
二次机会页面置换算法:对FIFO的修改,如果表头的R位是0,则淘汰,若为1,则将R清零,并放回表尾。
4.在某请求分页管理系统中,一个进程共5页,进程执行时一次访问如下页面:2 3 2 1 5 2 4 5 3 2 5 2,若分配给该进程的页框数为3,采用FIFO页面置换算法,其缺页率为()。
A.6 B.9 C.8 D.7
B
5.在某请求分页管理系统中,一个进程共5页,进程执行时一次访问如下页面:2 3 2 1 5 2 4 5 3 2 5 2,若分配给该进程的页框数为3,采用LRU页面置换算法,其页面置换次数为()。
A.4 B.3 C.6 D.5
A
感觉LRU算法就是先从上到下,再从下往上,1 2 3 2 1这样的顺序。
这道题要注意的是缺页中断和页面置换不一样,缺页中断次数-页框数=页面置换次数。
在请求分页系统中,可以通过查询页表中的状态位来确定所要访问的页面是否存在于内存中。每当所要访问的页面不在内存时,会产生一次缺页中断,此时操作系统会根据页表中的外存地址在外存中找到所缺的一页,将其调入内存。
页面置换是进程运行过程中,如果发生缺页中断,而此时内存中有没有空闲的物理块是,为了能够把所缺的页面装入内存,系统必须从内存中选择一页调出到磁盘的对换区。