三、内存管理 (二)虚拟存储器
目录
2.1虚拟内存的基本概念
2.2内存分配策略
2.2.1驻留集大小
2.2.2固定分配局部置换
2.2.3可变分配全局置换
2.2.4可变分配局部置换
2.3地址变换机构
2.3.1页表机制
2.3.2预调页策略和请求调页策略
2.3.3缺页中断机构
2.3.4对换区与文件区
2.3.5页面置换算法
2.3.5.1最佳(OPT)置换算法
2.3.5.2先进先出(FIFO)页面置换算法
2.3.5.3最近最久未使用置换算法
2.3.5.4时钟(CLOCK)置换算法
2.3.5.5改进型CLOCK置换算法
2.3.6抖动和工作集
2.1虚拟内存的基本概念
前面介绍的连续分配管理方式、基本分页(分段、段页)管理方式等传统内存管理策略具有以下两个特征:
- 一次性。作业必须一次性全部装入内存后,才能开始运行。
- 驻留性。作业被装入内存后,就一直驻留在内存中。
虚拟内存技术实际上是建立了“内存——外存”的两级存储结构,为了解决内存容量小的问题。而“cache——内存”层是为了解决CPU和主存速度不一致的问题。两者在问题与解决方法上有许多共同点。
系统好像为用户提供了一个比实际内存容量大得多的存储器,称为虚拟存储器。
虚拟内存技术具有以下特征:
- 多次性。是指无须在作业运行时一次性全部装入内存,只需将当前要运行的那部分程序和数据装入内存即可开始运行。以后每当要运行到尚未调入的那部分程序,再将它调入。是虚拟存储器最重要的特征。
- 对换性。是指无须在作业运行时一直常驻内存,在进程运行期间,允许将那些暂时不使用的程序和数据从内存调至外存的对换区(换出),待以后需要时再将它们从外存调至内存(换进)。正是由于对换性,虚拟存储器才得以正常运行。
实现上述特征之后,虚拟存储器就有了虚拟性,即用户看到的内存容量远大于实际的内存容量。
我们应该以之前小节讨论的传统存储器管理方式为基础来增加虚拟性的特点,很明显连续分配方式每个分区空间过大,无法从逻辑上扩大内存容量。因此主要有请求分页存储管理、请求分段存储管理、请求段页存储管理三种方式。
不管哪种方式都需要有一定的硬件支持,这也是下面讨论的重点方面:
- 一定容量的内存和外存。
- 页表机制、段表机制(应该增加一些功能来实现虚拟性)
- 中断机构。当用户程序要访问的部分尚未调入内存时,则产生中断。
- 地址变换机构(虚实地址的转变即逻辑地址到物理地址)
进而有以下问题:
- 2.2新的页框分配策略(传统方式因为要全部放入内存基本和进程大小一致)
- 2.3地址变换机构(为了实现虚拟内存需要增加什么功能)
- 2.3.1页表机制(页表需要增加什么字段)
- 2.3.2调入页面的时机(要确定系统将进程运行时所缺的页面调入内存的时机)
- 2.3.3缺页中断机构(发生缺页时的处理)
- 2.3.4从何处调入页面(磁盘I/O操作的处理也会影响虚拟存储器的性能)
- 2.3.5页面置换算法(内存已无空闲空间时选择调出页面的算法)
2.2内存分配策略
2.2.1驻留集大小
驻留集:指请求分页存储管理中给进程分配的物理块的集合。 在采用了虚拟存储技术的系统中,驻留集大小一般小于进程的总大小。若驻留集太小,会导致缺页频繁,系统要花大量的时间来处理缺页,实际用于进程推进的时间很少;若驻留集太大,又会导致多道程序并发度下降,资源利用率降低。
固定分配:操作系统为每个进程分配一组固定数目的物理块,在进程运行期间不再改变。即,驻留集大小不变。
可变分配:先为每个进程分配一定数目的物理块,在进程运行期间,可根据情况做适当的增加或减少,即驻留集大小可变。
局部置换:发生缺页时只能选进程自己的物理块进行置换。
全局置换:可以将操作系统保留的空闲物理块分配给缺页进程,也可以将别的进程持有的物理块置换到外存,再分配给缺页进程。
没有固定分配全局置换这种方式,因为这种方式进行全局置换时必定会破坏驻留集大小不变这个特点,产生矛盾。
2.2.2固定分配局部置换
采用固定分配局部置换策略时可以采用以下的物理块调入算法:
- 平均分配算法。平均分配给每一个进程。
- 按比例分配算法。根据进程的大小按比例分配物理块。
- 优先权分配算法。为重要和紧迫的进程分配较多物理块。通常也可以采用部分按比例分配,部分按优先权分配的策略。
2.2.3可变分配全局置换
2.2.4可变分配局部置换
- 可变分配全局置换:只要缺页就给分配新物理块。
- 可变分配局部置换:要根据发生缺页的频率来动态地增加或减少进程的物理块。
2.3地址变换机构
补充细节:
- 只有“写指令”才需要修改“修改位”。并且,一般来说只需修改快表中的数据,只有要将快表项删除时才需要写回内存中的慢表。这样可以减少访存次数。
- 和普通的中断处理一样,缺页中断处理仍然需要保留CPU现场。
- 需要用某种“页面置换算法”来决定一个换出页面
- 换入/换出页面都需要启动慢速的I/O操作,可见如果换入/换出太频繁会有很大开销。
- 页面调入内存后,需要修改慢表,同时也需要将表项复制到快表中。
2.3.1页表机制
可以与cache块内容进行对比学习。cache行位数=标记位(tag)+有效位+替换控制位+修改位+数据位。
状态位和有效位功能类似,一个是判断是否调入内容,一个是判断是否调入Cache。
访问字段和替换控制位功能类似,一个是用于页面置换算法参考,一个是用于cache替换算法参考。
修改位和修改位(脏位)功能类似,一个是判断调入内存后是否修改过,一个是判断调入Cache后是否修改过。
标记位(tag)、数据位。标记位的作用是判断是否命中cache,数据位是相应的块的存储信息。
内存块号、外存块号。内存块号是用来进行虚实地址转换,外存块号是为了缺页时调入内存。
2.3.2预调页策略和请求调页策略
预调入实际上就是运行前的调入,请求调页实际上就是运行期间调入。
2.3.3缺页中断机构
缺页中断是因为当前执行的指令想要访问的目标页面未调入内存而产生的,因此属于内中断中的故障(fault)。
一条指令在执行期间,可能产生多次缺页中断。(如:copyAtoB,即将逻辑地址A中的数据复制到逻辑地址B,而A、B属于不同的页面,则有可能产生两次中断)
2.3.4对换区与文件区
2.3.5页面置换算法
2.3.5.1最佳(OPT)置换算法
最佳置换算法(OPT,Optimal):每次选择淘汰的页面将是以后永不使用,或者是最长时间不再被访问的页面,这样可以保存最低的缺页率。
操作系统无法提前预判页面访问序列,因此这是一种无法实现的算法
2.3.5.2先进先出(FIFO)页面置换算法
先进先出置换算法(FIFO,first in first out):每次选择淘汰的页面是最早进入内存的页面。
实现方法:把调入内存的页面根据调入的先后顺序排成一个队列,需要换出页面时选择队头页面即可,队列的最大长度取决于系统为进程分配了多少个内存块。
2.3.5.3最近最久未使用置换算法
最近最久未使用置换算法(LRU,least recently used):每次淘汰的页面是最近最久未使用的页面。
实现方法:用访问字段记录该页面自上次被访问以来所经历的时间t。当需要淘汰一个页面时,选择现有页面中t值最大的,即最近最久未使用的页面。
实现起来需要专门的硬件支持,算法开销大。
2.3.5.4时钟(CLOCK)置换算法
时钟置换算法又称CLOCK算法或最近未用算法(NRU,not recently used)
- 第一轮:扫描整个循环队列,为1的就改为0在继续循环,尝试找到一个访问位为0的置换。
- 第二轮:由于上一轮全是1才进入了第二轮,那么目前第二轮的第一个必是0。
2.3.5.5改进型CLOCK置换算法
- 按照未访问,未修改→未访问,修改→访问,未修改→访问,修改的次序进行。即以简单时钟置换算法为标准(访问位重要)
2.3.6抖动和工作集
刚刚换出的页面马上又要换入内存,刚刚换入的页面马上又要换出外存,这种频繁的页面调度行为称为抖动,或颠簸。产生抖动的主要原因是进程频繁访问的页面数目高于可用的物理块数(分配给进程的物理块不够)
一般来说,驻留集不能小于工作集,否则进程运行过程中将频繁缺页。