5.1 前备知识
常规存储管理方式的特征:
- 一次性:要求一个作业全部装入内存后方能运行。
- 驻留性:作业装入内存后一直驻留内存,直至结束。
局部性原理
-
指程序在执行过程中的一个较短时期,所执行的指令地址和指令的操作数地址,分别局限于一定区域。还可以表现为
-
时间局部性:即指令的一次执行和下次执行,数据的一次访问和下次访问都集中在一个较短时期内;
-
空间局部性:即当前指令和邻近的几条指令,当前访问的数据和邻近的数据都集中在一个较小区域内
-
程序的局部性
- 程序在执行时,大部分是顺序执行的指令,少部分是转移和过程调用指令。
- 过程调用的嵌套深度一般不超过5,因此执行的范围不超过这组嵌套的过程。
- 程序中存在相当多的循环结构,它们由少量指令组成,而被多次执行。
- 程序中存在相当多对一定数据结构的操作,如数组操作,往往局限在较小范围内
可能出现的问题:
- 有的作业很大,所需内存空间大于内存总容量,使作业无法运行。
- 有大量作业要求运行,但内存容量不足以容纳下所有作业,只能让一部分先运行,其它在外存等待。
解决方法:
- 增加内存容量
- 从逻辑上扩充内存容量:覆盖、对换。
5.2 虚拟存储
虚拟存储是计算机系统存储管理的一种技术。
- 给所有进程提供一致的地址空间,每个进程都认为自己是在独占使用单机系统的存储资源;
- 保护每个进程的地址空间不被其他进程破坏,隔离了进程的地址访问
- 虚拟内存把主存作为磁盘的高速缓存,在主存和磁盘之间根据需要来回传送数据,高效地使用了主存
虚拟存储的基本原理:按需装载、缺页调入、不用调出
虚拟存储技术的特征
- 离散性:物理内存分配的不连续,虚拟地址空间使用的不连续(数据段和栈段之间的空闲空间,共享段和动态链接库占用的空间)
- 多次性(分时复用):作业被分成多次调入内存运行。正是由于多次性,虚拟存储器才具备了逻辑上扩大内存的功能。多次性是虚拟存储器最重要的特征
- 对换性:允许在作业运行过程中进行换进、换出。换进、换出可提高内存利用率
- 虚拟性:虚拟存储器机制允许程序从逻辑的角度访问存储器,而不考虑物理内存上可用的空间数量
虚拟性以多次性和对换性为基础
多次性和对换性必须以离散分配为基础
优点:
- 可在较小的可用内存中执行较大的用户程序;
- 可在内存中容纳更多程序并发执行;
- 不必影响编程时的程序结构(与覆盖技术比较)(对用户(编程人员)透明)
- 提供给用户可用的虚拟内存空间通常大于物理内存(real memory)
代价:虚拟存储量的扩大是以牺牲 CPU 工作时间以及内外存交换时间为代价。
限制:虚拟内存的最大容量=min{计算机的地址位数(主),内外存容量和}
与Cache-主存机制的异同
-
相同点:
-
出发点相同:二者都是为了提高存储系统的性能价格比而构造的分层存储体系,都力图使存储系统的性能接近高速存储器,而价格和容量接近低速存储器。
- 原理相同:都是利用了局部性原理把最近常用的信息块从相对慢速而大容量的存储器调入相对高速而小容量的存储器。
-
-
不同点:
-
侧重点不同:cache主要解决主存与CPU的速度差异问题;虚存主要解决存储容量问题,另外还包括存储管理、主存分配和存储保护等方面
-
数据通路不同:CPU与cache和主存之间均有直接访问通路,cache不命中时可直接访问主存;而虚存所依赖的辅存与CPU之间不存在直接的数据通路,当主存不命中时只能通过调页解决,CPU最终还是要访问主存。
-
透明性不同:cache的管理完全由硬件完成,对系统程序员和应用程序员均透明;而虚存管理由软件(OS)和硬件共同完成,由于软件的介入,虚存对实现存储管理的系统程序员不透明,而只对应用程序员透明(段式和段页式管理对应用程序员“半透明”)。
-
未命中时的损失不同:由于主存的存取时间是cache的存取时间的5~10倍,而主存的存取速度通常比辅存的存取速度快上千倍,故主存未命中时系统的性能损失要远大于cache未命中时的损失。
-
5.3 请求分页(段)系统
系统需设置相应的硬件支持和软件:
- 硬件支持:请求分页(段)的页(段)表机制、缺页(段)中断机构和地址变换机构。
- 软件:请求调页(段)功能和页(段)置换功能的软件。
请求分页与分段系统的比较
- 基本单位:分别为页、段
- 长度:分别为固定、可变
- 分配方式:分别为固定分配、可变分配
- 复杂度:分别为较简单、较复杂
虚存机制要解决的关键问题
- 地址映射问题:进程空间到虚拟存储的映射问题。
- 调入问题:决定哪些程序和数据应被调入主存,以及调入机制。
- 替换问题:决定哪些程序和数据应被调出主存。
- 更新问题:确保主存与辅存的一致性。
- 其它问题:存储保护与程序再定位等问题
在操作系统的控制下,硬件和系统软件为用户解决了上述问题,从而使应用程序的编程大大简化。
虚拟地址空间和虚拟存储空间
- 一个进程的虚拟地址空间的大小与该进程的虚拟存储空间的大小相同。且都从0开始编址,有些书中也将虚拟存储空间称虚拟内存空间。
- 含有空白的虚拟地址空间称为稀疏地址空间
- 进程的逻辑空间也称虚拟空间
进程空间到虚存空间的映射(进程的虚存分配)
- 在程序装入时,由装载器(Loader)完成。
- 分配是以段为单位(需页对齐)进行的。
- 事实上,在每个进程创建加载时,内核只是为进程"创建"了虚拟内存的布局,实际上并不立即就把虚拟内存对应位置的程序数据和代码(比如.text .data段)拷贝到物理内存中,只是建立好虚拟内存和磁盘文件之间的映射 (叫做存储器映射),等到运行到对应的程序时,才会通过缺页异常,来拷贝数据。
- 用户可执行文件(如Hello World可执行文件)及共享库(如HelloWorld中调用的库文件中的printf函数)都是以文件的形式存储在磁盘中,初始时其在页表中的类型为file backed,地址为相应文件的位置。
- 堆(heap)和栈(stack)在磁盘上没有对应的文件,页表中的类型为anonymous,地址为空。
- 未分配部分没有对应的页表项,只有在申请时(如使用malloc( )申请内存或用mmap( )将文件映射到用户空间)才建立相应的页表项。
页表机制
- 驻留位/状态位:1表示该页位于内存当中,0表示该页当前还在外存中
- 保护位:只读,可写,可执行
- 修改位:表明此页在内存中是否被修改过,确保内存与外存数据一致
- 访问(统计)位:用于页面置换算法,记录本页在一段时间内访问的次数/已有多长时间未被访问
Intel处理器的PDE和PTE
调入问题
- 什么程序和数据调入主存?
- OS的核心部分的程序和数据;
- 正在运行的用户进程相关的程序及数据。
- 何时调入?
- OS在系统启动时调入。
- 用户程序的调入取决于调入策略。常用的调度策略有∶
- 预调页∶ 事先调入页面的策略。
- 按需调页∶仅当需要时才调入页面的策略。
- 如何调入:缺页错误处理机制。
缺页中断机构
- 访问页不再内存中时,产生缺页中断,由OS的缺页中断处理程序处理
- 缺页的进程阻塞,调页完成后再唤醒
- 若内存中有空闲块,则分配;若没有空闲块,则淘汰某页(若修改位为1则要写回外存)
更新问题
在虚存系统中,主存作为辅存(磁盘)的高速缓存,保存了磁盘信息的副本。因此,当一个页面被换出时,为了保持主辅存信息的一致性,必要时需要信息更新:
- 若换出页面是file backed类型,且未被修改,则直接丢弃,因为磁盘上保存有相同的副本。
- 若换出页面是file backed的类型,但已被修改,则直接写回原有位置。
- 若换出页面是anonymous类型,若是第一次换出且未被修改,则写入Swap区,若非第一次则丢弃。
- 若换出页面是anonymous类型,且已被修改,则写入Swap区
内存分配策略
局部置换:在进程自身的驻留集中置换;全局置换:在整个内存空间中置换
-
进程划分的额外约束
- 固定分配局部置换
- 可变分配全局置换
- 可变分配局部置换
-
页面分配策略:
- 可变分配比固定分配更灵活,既可以提高系统的吞吐量,又能保证内存的有效利用。
- 但可变分配要求统计进程的缺页率,增加系统额外开销。而准确判断进程缺页率的高低,确定缺页率的阈值是非常困难的。
地址变换机构
调入页面的时机
-
预调页
-
一次性加载比较多的常用页(这些页往往相邻,局部性原理),使得缺页次数最小。
-
进程开始的时候,所有页都在磁盘上,每个页都需要通过页错误来调入内存。
-
预调页有时效果较好,有时可能页并没有被使用。成本不一定小于不使用预调页时发生页错误的成本
-
主要用于进程的首次调用
-
-
按需调页
-
类似于使用交换的分页系统,进程驻留在二级存储器上(磁盘),进程执行时使用 懒惰交换(lazy swapper)换入内存
-
需要备份存储,保留不在内存中的页,通常为快速磁盘,用于和内存交换页的部分空间称为交换空间(swap space)
请求分页的外存分为两部分:用于存放文件的文件区(离散分配)、用于存放对换页面的对换区(连续分配方式)
-
缺页错误处理机制(重点)
缺页错误处理过程
当进程执行过程中需访问的页面不在物理存储器中时,会引发发生缺页中断,进行所需页面换入,步骤如下:
- 陷入内核态,保存必要的信息(OS及用户进程状态相关的信息)。(现场保护)
- 查找出来发生页面中断的虚拟页面(进程地址空间中的页面)。这个虚拟页面的信息通常会保存在一个硬件寄存器中,如果没有的话,操作系统必须检索程序计数器,取出这条指令,用软件分析该指令,通过分析找出发生页面中断的虚拟页面。(页面定位)
- 检查虚拟地址的有效性及安全保护位。如果发生保护错误,则杀死该进程。(权限检查)
- 查找一个空闲的页框(物理内存中的页面),如果没有空闲页框则需要通过页面置换算法找到一个需要换出的页框。(新页面调入(1))
- 如果找的页框中的内容被修改了,则需要将修改的内容保存到磁盘上¹。(注:此时需要将页框置为忙状态,以防页框被其它进程抢占掉)(旧页面写回)
- 页框“干净”后,操作系统将保存在磁盘上的页面内容复制到该页框中²。(新页面调入(2))
- 当磁盘中的页面内容全部装入页框后,向操作系统发送一个中断。操作系统更新内存中的页表项,将虚拟页面映射的页框号更新为写入的页框,并将页框标记为正常状态。(更新页表)
- 恢复缺页中断发生前的状态,将程序指针重新指向引起缺页中断的指令。(恢复现场)
- 程序重新执行引发缺页中断的指令,进行存储访问。(继续执行)
¹² 此时会引起一个磁盘读写调用,发生上下文切换(在等待磁盘读写的过程中让其它进程运行)。
缺页处理过程涉及了用户态和内核态之间的切换,虚拟地址和物理地址之间的转换(这个转换过程需要使用MMU和TLB)
(用自己的话描述此图)
5.4 页面置换
页面置换策略【王道P206】
-
最优置换(OPT算法)
-
置换掉未来最久不被使用的页
-
需要引用先验知识(知道未来所有被调入的页的号码),因此无法被实现
-
通常用于比较性研究,衡量其他页置换算法的效果
-
-
先进先出算法(FIFO)
-
性能较差,可能出现Belady异常(随着分配的页框增多,缺页率反而提高的现象)
-
改进的FIFO——Second chance
-
-
最近最久不用的页面置换算法(LRU)
- 选择在最近一段时间内最久不用的页面予以淘汰
-
时钟置换(CLOCK/NRU(最近未用))
- 为每个帧设置一位访问位,当某页首次被装入/被访问时,访问位置为1
- 循环队列。替换指针指向上次替换位置的下一帧
- 选择一页淘汰时,检查页的访问位,如果为0则换出,如果为1则将其置为0,暂不换出,给予该页第二次驻留内存的机会。
- 改进型CLOCK算法【王道P208】
5.5 工作集与驻留集管理
进程的工作集(working set):某段时间间隔内,进程要访问的页面集合。设工作集窗口大小为5
- 需要进行页面替换时,选择不在工作集中的页面进行替换。
- 一般分配给进程的物理块数(驻留集大小)> 工作集大小
进程的驻留集(Resident Set):给一个进程分配的物理页框的集合就是这个进程的驻留集
工作集的动态变化
- 进程开始执行后,随着不断访问新页面逐步建立较稳定的工作集。
- 当内存访问的局部性区域的位置大致稳定时,工作集大小也大致稳定;
- 局部性区域的位置改变时,工作集快速扩张和收缩过渡到下一个稳定值。
获取准确工作集的困难
- 过去变化不一定代表未来变化
- 开销大
- 对工作集窗口大小$\triangle $的取值难以优化,且该值是不断变化的。
驻留集的管理
- 进程驻留集管理主要解决的问题是,系统应当为每个活跃进程分配多少个页框。
- 影响页框分配的主要因素:
- 分配的页框数越少,驻留内存的活跃进程数就越多,进程能调度更多的就绪程序,但进程发生缺页中断的概率增大;
- 为进程分配过多的页框,并发运行的进程数降低,影响资源利用率
抖动/颠簸问题
- 随着驻留内存的进程数目增加,或者说进程并发水平的上升,处理器利用率先是上升,然后下降
- 这里处理器利用率下降的原因通常称为虚拟存储器发生“抖动”,也就是:每个进程的驻留集不断减小,当驻留集小于工作集后,缺页率急剧上升,频繁调页使得调页开销增大。(导致CPU利用率)
抖动的预防与消除
- 局部置换策略
- 如果一个进程出现抖动,它不能从另外的进程那里夺取内存块,从而不会引发其他进程出现抖动,使抖动局限于一个小的范围内。 然而这种方法并未消除抖动的发生。(微观层面)
- 引入工作集算法(微观
- 预留部分页面(微观或宏观
- 挂起若干进程(宏观)
改善时间性能的途径
- 降低缺页率
- 缺页率越低,虚拟存储器的平均访问时间延长得就越小
- 提高外存的访问速度
- 外存和内存的访问时间比值越大,则达到同样的时间延长比例,所要求的缺页率就越低
- 高速缓存命中率
虚拟内存其它用途
写时拷贝、内存映射