操作系统-第三章
内存
内存的基础知识
什么是内存,有何作用
存储单元,内存地址的概念和联系
- 内存可存放数据。程序执行前需要先放到内存中才能被CPU处理–缓和CPU与硬盘之间的速度矛盾
- 内存地址从0开始,每个地址对应一个存储单元
- 内存中也有一个一个的“小房间”,每个小房间就是一个“存储单元”
- 计算机去“按字节编址”,则每个存储单元大小为1字节,1B 8bit
- 如果字长为16位的计算机,“按字编址”,则每个存储单元大小位1个字
进程运行的基本原理
指令的工作原理
操作码+若干参数(可能包含地址参数)
逻辑地址(相对地址)VS 物理地址(绝对地址)
三种装入方式
- 绝对装入:编译时产生绝对地址
- 可重定位装入(静态重定位):装入时将逻辑地址转换为物理地址(必须分配其要求的全部内存空间)
- 动态运行时装入(动态定位):运行时将逻辑地址转换为物理地址(重定位寄存器)允许程序在内存中发生移动
从写程序到程序运行
- 编辑源代码文件
- 编译:由源代码文件生成目标模块(高级语言翻译为机器语言)
- 连接:由目标模块生成装入模块,链接后形成完整的逻辑地址
- 装入:将装入模块装入内存,装入后形成物理地址
三种链接方式
- 静态链接:装入前链接成一个完整装入模块
- 装入时动态链接:运行前边装入边链接
- 运行时的动态链接:运行时需要目标模块才装入并连接
内存管理的概念
- 操作系统负责内存空间的分配与回收
- 操作系统需要提供某种技术从逻辑上对内存空间进行扩充(实现虚拟性)
- 操作系统需要提供地址转换功能,负责程序的逻辑地址与物理地址的转换
三种装入方式:
绝对装入:编译器负责地址转换(单道程序阶段,无操作系统)
可重定位装入:装入程序负责地址转换(早期多道批处理阶段)
动态运行时装入:运行时才进行地址转换(现代操作系统)
- 操作系统需要提供内存保护功能,保存各进程在各自存储空间内运行,互不干扰
两种方式
设置上下限寄存器,在CPU中设置一对上,下限寄存器
采用重定位寄存器(又称为基址寄存器)和界地址寄存器(又称限长寄存器)进行越界检查,重定位寄存器中存放的是进程的起始物理地址。界地址寄存器中存放的是进程的最大逻辑地址
覆盖与交换
覆盖技术(树)
人们引入覆盖技术,用来解决“程序大小超过物理内存总和”的问题
思想:将程序分为多个段(多个模块)
常用的段常驻内存,不常用的段在需要时调入内存
一个固定区
- 存放最活跃的程序段
- 固定区中的程序段在运行过程中不会调入调出(调入后就不再调出)
若干覆盖区
- 不可能同时被访问程序段可共享一个覆盖区
- 覆盖区中的程序段在运行过程中会根据需要调入调出(需要时调入内存,用不到时调出内存)
必须由程序员声明覆盖结构,操作系统完成自动覆盖
缺点:对用户不透明,增加了用户编程负担
交换技术
- 内存紧张时,换出某些进程以腾出内存空间,再换入某些进程
暂时换出外存等待的进程状态为挂起状态
挂起状态又可以进一步细分为就绪挂起,阻塞挂起
- 磁盘分为文件区和对换区,换出的进程放在对换区
文件区主要用于存放文件,主要追求存储空间的利用率,因此对文件区空间的管理采用离散分配方式;对换区空间只占磁盘空间的小部分,被换出的进程数据就存放在对换区
对换的速度直接影响到系统的整体速度,因此对换区空间的管理主要追求换入换出速度,因此通常对换区连续分配方式
对换区的I/O速度比文件区的更快
注意:PCB会常驻内存,不会被换出外存
覆盖与交换的区别
- 覆盖是在同一个程序或进程中的
- 交换是在不同进程(作业)中
连续分配管理
单一连续分配
-
只支持单道程序,内存分为系统区和用户区,用户程序独占整个在用户区
-
系统区通常位于内存的低地址部分,用于存放操作系统相关数据;用户区用于存放用户进程相关数据
-
无外部碎片,有内部碎片
-
优点
-
实现简单;无外部碎片;可用采用覆盖技术扩充内存,不一定需要采取内存保护
-
缺点
-
只能用于单用户,单用户的操作系统中;有内部碎片;存储器利用率极低
固定区分配
-
支持多道程序,内存用户空间分为若干个固定大小的分区,每个分区只能装一道作业
-
无外部碎片,有内部碎片
-
两种分区方式
-
分区大小相等
缺少灵活性,适用于用一台计算机控制多个相同对象的场合
分区大小不等
-
操作系统需要建立一个数据结构–分区说明表,来实现各个分区的分配与回收。每个表项对应一个分区,通常按分区大小排列。每个表项包括对应分区的大小,起始地址,状态
-
优点:实现简单,无外存碎片
-
缺点:a.当用户程序太大时,可能所有的分区都不能满足需求,此时不得不采用覆盖技术来解决,这又会降低性能;b.会产生内部碎片,内存利用率低
动态区分配
- 支持多道程序,在进程装入内存时,根据进程的大小动态地建立分区
- 无内部碎片,有外部碎片
- 外部碎片可用“紧凑”技术来解决
- 回收内存分区时,可能遇到四种情况
回收区之后有相邻的空闲分区
回收区之前有相邻的空闲分区
回收区前,后都有相邻的空闲分区(以上合并)
回收区前,后都没有相邻的空闲分区(新增)
- 常用的两种数据结构
空闲分区表:表中包含分区号,分区大小,分区起始地址等信息
空闲分区链:每个分区的起始部分和末尾部分分别设置前向指针和向后指针,起始部分还可记录分区大小等信息
动态分区分配算法
首次适应
-
算法思想
-
从头到尾找适合的分区
-
分区排列顺序
-
空闲分区以地址递增次序排列
-
优点
-
综合看性能最好,算法开销小,回收分区后一般不需要对空闲分区队列重新排序
最佳适应
-
算法思想
-
优先使用更小的分区,以保留更多大分区
-
分区排列顺序
-
空闲分区以容量递增次序排序
-
优点
-
会有更多的大分区被保留下来,更能满足大进程需求
-
缺点
-
会产是太小的,难以利用的碎片;算法开销大,回收分区后可能需要对空闲分区队列重新排序
最坏适应
-
算法思想
-
优先使用更大的分区,以防止产生太小的不可用的碎片
-
分区排列顺序
-
空闲分区以容量递减次序排序
-
优点
-
可用减小难以利用的小碎片
-
缺点
-
大分区容易被用完,不利于大进程;算法开销大,回收分区后可能需要对空闲分区队列重新排序
邻近适应
-
算法思想
-
由首次适应演变而来,每次从上次查找结束位置开始查找
-
分区排列顺序
-
空闲分区以地址递增次序排列(可排列成循环链表
-
优点
-
不用每次都从低地址的小分区开始检索。算法开销小
-
缺点
-
会使高地址的大分区被用完
基本分页存储管理的基本概念
-
基本分页存储管理的思想:把进程分页,各个页面可离散地放在各个内存块中(混淆概念
-
“页框,页帧,内存块,物理块,物理页” VS “页,页面”
“页框号,页帧号,内存块号,物理块号,物理页号” VS “页号,页面号”
- 将内存空间分为一个个大小相等的分区,每个分区就是一个“页框”,页框号从0开始
- 将进程的逻辑地址空间分为与页框大小相等的一个个部分,每个部分称为“页”,页号也是从0开始
- 操作系统以页框为单位为各个进程分配内存空间。进程的每个页面分别放入一个页框中。进程的页面与内存的页框有一一对应的关系
-
页表
-
- 页表记录了页面和实际存放的内存块之间的映射关系
- 一个进程对应一张页表,进程的每一页对应一个页表项,每个页表项由“页号”和“块号”组成
- 每个页表项的大小是相同的,页号是“隐含”的
- i号页表项存放地址 = 页表始址 + i * 页表项大小
-
逻辑地址结构----可拆分为【页号P,页内偏移量W】
-
-
页号 = 逻辑地址/页面大小; 页内偏移量 = 逻辑地址%页面大小
-
如果页面大小刚好是2的整数倍
-
如果每个页面大小为2的k次方B,末尾K位即为页内偏移量,其余部分位页号
-
-
如何实现地址转换
-
- 计算出逻辑地址对应的【页号,页内偏移量】
- 找到对应页面在内存中的存放位置【查页表】
- 物理地址 = 页面始址 + 页内偏移量
如果有K位表示 “页内偏移量” ,则说明系统中一个页面的大小是2的k次方个内存单元
如果有M位表示 “ 页号 ",则说明系统中,一个进程最多允许有2的M个页面
页面大小《----- 》页内偏移量—》逻辑地址结构
基本地址变换机构
页表寄存器的作用
- 存放页表起始地址F
- 存放页表长度M
- 进程未执行时,页表的起始地址和页表长度存放在进程控制块(PCB)中,当进程被调度时,操作系统内核会把他们放在页表寄存器中
地址变换过程
- 根据逻辑地址算出页号,页内偏移量
- 页号的合法性检查(与页表长度对比)
比较页号P和页表长度M,若P>=M,则会产生越界中断,否则继续执行
- 若页号合法,在根据页表起始地址,页号找到对应页表项
页表中页号P对应的页表项地址=页表起始地址F + 页号P * 页表项长度
-
根据页表项中记录的内存块号,页内偏移量得到最终的物理地址
-
访问物理内存相应的内存单元
其他小细节
- **页内偏移量位数与页面大小之间的关系(要能用其中一个条件推出另一个条件)(页内偏移量位数=页面大小的位数
- **页式管理中地址是一维的
- 实际应用中,通常使一个页框恰好能放入整数个页表项
- 为了方便找到页表项,页表一般使存放在连续的内存块中
具有快表的地址变换机构
基本地址变换机构
地址变换过程
- 算页号,页内偏移量
- 检查页号合法性
- 查页表,找到页面存放的内存块
- 根据内存块号与页内偏移量得到物理地址
- 访问目标内存单元
访问一个逻辑地址的访存次数
两次访存
具有快表的地址变换机构
地址变换过程
- 算页号,页内偏移量
- 检查页号合法性
- 查快表。若命中,即可知道页面存放的内存块号,可直接进行(5),若未命中则进程(4)
- 查页表,找到页面存放的内存块号,并将页表项复制在快表中
- 根据内存块号与页内偏移量得到物理地址
- 访存目标内存单元
访问一个逻辑地址的访存次数
快表命中,只需一次访存
快表未命中,需要两次访存
快表(TLB)
快表,又称联想寄存器,是一种访问速度比内存快很多的 高速缓存(TLB不是内存),用来存放最近访问的页表项的副本,可以加速地址变换的速度。内存中的页表常称为慢表
时间局部性:如果执行了程序中的某条指令(数据),那么不久后这条指令很可能再次被执行(访问)
空间局部性:一旦访问了某个存储单元,在不久后,其附近的存储单元也很可能被访问
两级页表
单级页表存在的问题
- 所有页表项必须连续存放,页表过大时需要很大的连续空间
- 在一段时间内并非所有页面都用得到,因此没必要让整个页表常驻内存
两级页表
- 将长长的页表再分页
- 逻辑地址结构:(一级页号,二级页号,页内偏移量)
- 注意几个术语:页目录表/外层页表/顶级页表
如何实现地址变换
- 按照地址结构将逻辑地址拆分成三部分
- 从PCB中读出页目录表始地址,根据一级页号查页目录表,找到下一级页表在内存中存放的位置
- 根据二级页号查表,找到最终想要访问的内存块号
- 结合页内偏移量得到物理地址
几个细节
-
多级页表中,各级页表的大小不能超过一个页面,若两级页表不够,可以分更多级
-
多级页表的访存次数(无快表机构)----N级页表访问一个逻辑地址需要N+1次访存
基本分段存储管理
分段
- 将地址空间按照程序自身的逻辑关系划分为若干段,每段从0开始编址(编程更方便,程序的可读性更高))
- 每个段在内存中占据连续空间,但各段之间可以不相邻
- 逻辑地址结构:(段号,段内地址)
段表
- 记录逻辑段到实际存储地址的映射关系
- 每个段对应一个段表项,各段表项长度相同,由段号(隐含),段长,基址组成
地址变换
- 由逻辑地址得到段号,段内地址
- 段号与段表寄存器中的段长度比较,检查是否越界
- 由段起始址,段号找到对应段表项
- 根据段表中记录的段长,检查段内地址是否越界
- 由段表中的“基址 + 段内地址”得到最终的物理地址
- 访问目标单元
分段 VS 分页
- 分页对用户不可见(页是信息的物理单位),分段对用户可见(段是信息的逻辑单位)
- 分页的地址空间时一维的,分段的地址空间时二维的
- 分段更容易实现信息的共享和保护(纯代码/可重入代码可以共享)
- 分页(单级页表),分段访问一个逻辑地址都需要两次访存,分段存储中也可以引入快表机构,可以减少一次访问
段页式管理
分段 + 分页
- 将地址空间按照程序自身的逻辑关系分为若干段,在将各段分为大小相等的页面
- 将内存空间分为与页面大小相等的一个个内存块,系统以块为单位为进程分配内存
- 逻辑地址结构:(段号,页号,页内偏移量)
段号的位数决定了每个进程最多可以分几个段
页号位数决定了每个段最大有多少页
页内偏移量决定了页面大小,内存块大小是多少
段页式管理的地址结构是二维的
每个段对应一个段表项,每个段表项由页号,页表长度,页表存放块号(页表起始地址)组成,每个段表项长度相等,段号是隐含的
分页,分段的优缺点分析
分页管理
- 优点:内存空间利用率高,不会产生外部碎片,只会有少量的页内碎片
- 缺点:不方便按照逻辑模块实现信息的共享和保护
分段管理
- 优点:很方便按照逻辑模块实现信息的共享和保护
- 缺点:如果段长过大,为其分配很大的连续空间会很不方便,另外,段式管理会产生外部碎片
段表 , 页表
- 每个段对应一个段表项,各段表项长度相同,由段号(隐含),页表长度,页表存放地址组成
- 每个页对应一个页表项,各页表项长度相同,由页号(隐含),页面存放的内存块号组成
地址变换
- 由逻辑地址得到段号,页号,页内偏移量
- 段号与段表寄存器中段长度比较,检查是否越界
- 由段表始址,段号找到对应段表项
- 根据段表长度,检查页号是否越界
- 根据段表中记录的页表地址,页号得到查询页表,找到相应页表项
- 由页面存放的内存块号,页内偏移量得到最终的物理地址
- 访问目标单元
访问一个逻辑地址所需访存次数
- 第一次-----查段表,第二次------查页表,第三次--------访问目标单元
- 可引入快表机构,以段号和页号为关键字查询快表,即可直接找到最终的目标页面存放位置,引入快表后仅需一次访存
虚拟内存
虚拟内存的基本概念
传统存储管理方式的特征,缺点
- 一次性:作业数据必须一次全部调入内存
- 驻留性:作业数据在整个运行期间都会常驻内存
局部性原理
- 空间局部性:现在访问的指令,数据在不久后可能会被再次访问
- 空间局部性:现在访问的内存单元周围的内存空间,很可能在不久后会被访问
- 高速缓存技术:使用频繁的数据放到跟高的存储器中
虚拟内存的定义和特征
-
程序不需要全部装入即可运行,运行时根据需要动态调入数据,若内存不够,还需换出一些数据
-
特征
-
- 多次性:无需在作业运行时一次性全部装入内存,而是允许被分成多次调入内存
- 对换性:无需再作业允许时一直常驻内存,而是允许再作业运行过程中,将作业换入,换出
- 虚拟性:从逻辑上扩充了内存的容量,使用户看到的内存容量,远大于实际容量
如何实现虚拟内存技术
-
访问的信息不在内存时,由操作系统负责将所需信息从外存调入内存(请求调页功能)
-
内存空间不够时,将内存中暂时用不到的信息换出外存(页面置换功能)
-
虚拟内存的实现
-
- 请求分页存储管理
- 请求分段存储管理
- 请求段页式存储管理
请求分页管理方式
-
请求分页存储管理与基本分页存储管理的主要区别:
-
- 访问的信息不再内存时,由操作系统负责将所需信息从外存调入内存
- 若内存空间不够,由操作系统负责将内存中暂时用不到的信息换出到外存
页表机制
- 在基本分页的基础上增加了几个表项
- 状态位:表示页面是否已在内存中
- 访问字段:记录最近被访问过几次,或记录上次访问的时间,供置换算法选择换出页面时参考
- 修改位:表示页面调入内存后是否被修改过,只有修改过的页面才需在置换时写回内存
- 外存地址:页面在外存中存放的位置
缺页中断机构
-
找到页表项后检查页面是否已在内存中,若没在内存,产生缺页中断,然后由操作系统的缺页中断处理程序处理中断,此时缺页的进程阻塞,访问阻塞队列,调页完成后再将其唤醒,放回就绪队列
-
缺页中断处理中,需要将目标页面调入内存,有必要时还要换出页面
-
如果内存中有空闲块,则为进程分配一个空闲块,将所缺页面装入该块,并修改页表中相应的页表项
如果内存中没有空闲块,则由页面置换算法选择一个页面淘汰,若该页面在内存期间被修改过,则要将其写回外存,未修改过的页面不用写回外存
-
缺页中断属于内中断,属于内中断中的“故障”,即可能被系统修复的异常
-
中断的分类
内中断(内部异常):陷阱,陷入(有意而为之的异常,eg:系统调用);故障(由错误条件引起的,可能被故障处理程序修复,eg:缺页中断);终止(不可恢复的致命错误造成的结果,终止处理程序不再将控制返回给引发终止的应用程序,eg:整数除0 )
外中断:I/O中断请求异常;人工干预
-
一条指令在执行过程中可能产生多次缺页中断
地址变换机构
- 找到页表项时需要检查页面是否在内存中
- 若页面不再内存中,需要请求调页
- 若内存空间不够,还需要换出页面
- 内存调入内存后,需要修改相应页表项
页面置换算法
OPT(最佳置换算法)
-
算法规则
-
优先淘汰最长时间内不会被访问的页面
-
优缺点
-
缺页率最小,性能最好;但无法实现
FIFO(先进先出算法)
-
算法规则
-
优先淘汰最先进入内存的页面
-
优缺点
-
实现简单;但性能很差,很可能出席Belady异常(当为进程分配分配的物理块数增大时,缺页次数不减反增的异常现象)
只有FIFO算法会产生Belady异常
LRU(最近最久未使用置换算法)
-
算法规则
-
优先淘汰最近最久没有访问的页面
-
优缺点
-
性能很好;但需要硬件支持,算法开销大
CLOCK(NRU)(时钟置换算法)
-
算法规则
-
算法扫描各页面
第一轮淘汰访问位=0的,并将扫描过的页面访问位改为1。若第一轮没选中,则进行第二轮扫描(最多访问两次)
-
优缺点
-
实现简单,算法开销小;但未考虑页面是否被修改过
改进型CLOCK(改进型NRU)
-
算法规则
-
若用(访问位,修改位)的形式表述,则
第一轮淘汰(0,0)
第二轮淘汰(0,1),并将扫描过的页面访问位都置为0
第三轮淘汰(0,0)
第四轮淘汰(0,1)
最多访问四次
-
优缺点
-
算法开销较小,性能也不错
页面分配策略
驻留集
-
指请求分页存储管理中给进程分配的内存块的集合(页面的数量)
(在采用虚拟存储技术的系统中,驻留集大小一般小于进程的总大小)
分配分配,置换策略
-
固定分配 VS 可变分配:区别在于进程运行期间驻留集大小是否可变
-
局部置换 VS 全局置换:区别在于发生缺页时是否只能从进程自己的页面中选择一个换出
-
固定分配局部置换:进程运行前就分配一定数量物理块,缺页时只能换出进程自己的某一页
-
可变分配全局置换:只要缺页就分配新物理块,可能来自空闲物理块,也可能需要换出别的进程页面
-
(若已无空闲物理块,则可选择一个未锁定的页面换出外存,再将该物理块分配给缺页的进程。只要某进程发生缺页,都将获得新的物理块,仅当空闲物理块用完时,系统才会选择一个未锁定的页面调出。这个被选中的进程拥有的物理块会减少,缺页率会增加)
只要缺页就给分配新物理块
-
可变分配局部置换:频繁缺页的进程,多分配一些物理块;缺页率很低的进程,回收一些物理块,直到缺页率合适
-
要根据缺页率动态的增加或减少进程的物理块
何时调入页面
- 预调页策略:一般用于进程运行前(主要用于进程的首次调入)
- 请求调页策略:进程运行时,发现缺页再调页。这种策略调入的页面一定会被访问到,但由于每次只能调入一页,而每次调页都要磁盘I/O操作,因此I/O开销较大
从何处调页
- 对换区------采用连续存储方式(读/写速度更快),速度更快;文件区------采用离散存储方式,速度更慢
- 对换区足够大:运行将数据从文件区复制到对换区,之后所有的页面调入,调出都是在内存与对换区之间进行
- 对换区不够大:不会修改的数据每次都从文件区调入;会修改的数据调出到对换区,需要时再从对换区调入
- UNIX方式:第一次使用的页面都从文件区调入;调出的页面都写回对换区,再次使用时从对换区调入
抖动(颠簸)现象
- 页面频繁的换入换出的现象,主要原因是分配给进程的物理块不够
工作集
- 在某段时间间隔里,进程实际访问页面的集合。驻留集大小不能小于工作集大小 ,否则进程运行过程中将频繁缺页
内存映射文件
操作系统向上层程序员提供的功能(系统调用)
方便程序员访问文件数据
传统的文件访问方式:
open系统调用------打开文件
seek系统调用------将读写指针移到某个位置
read系统调用------从读写指针所指位置读入若干数据(从磁盘读入内存)
write系统调用------将内存中的指定数据,写回磁盘(根据读写指针确定要写回什么位置)
内存映射文件的访问方式:
open系统调用------打开文件
mmap系统调用------将文件映射到进程的虚拟地址空间
- 以访问内存的方式访问文件数据
- 文件数据的读入,写出由操作系统自动完成
- 进程关闭文件时,操作系统自动将文件被修改的数据写回磁盘
- 多个进程可以映射同一个文件,实现**共享**
- 在物理内存中,一个文件对应同一份数据,当一个进程修改文件数据时,另一个进程可以立马“看到”
特性
- 进程可使用系统调用,请求操作系统文件映射到进程的虚拟内存空间
- 以访问内存的方式读写文件
- 进程关闭文件时,操作系统负责将文件数据写回磁盘,并解除内存映射
- 多个进程可以映射同一个文件,方便共享
优点
- 程序员编程更简单,已建立映射文件,只需按访问内存的方式读写即可
- 文件数据的读入/写出完全由操作系统负责,I/O效率可以由操作系统负责优化