CPU上电过程

1.BIOS-MBR-DBR

  • 读取BIOS(存储在内存-ROM中)

  • 大小1MB,有两个重要寄存器CS:IP,即代码段寄存器:指令指针寄存器

  • 系统处于实模式,只提供几个最基本的中断调用以实现IO功能(只能在实模式下调用)

  • 加电稳定后从FFFF:0000开始读取第一条JMP指令,跳转到自检指令段

    • POST(硬件自检):内存显卡等

    • 设备初始化:查找对应的接口卡并执行相应的BIOS

    • 系统检测:执行系统BIOS

  • 根据启动顺序跳转到下一阶段设备的启动程序,即跳转到对应的第一个扇区MBR

  • MBR(主引导记录)

  • 设备的第一个扇区,有512KB

  • 启动代码:检查分区表正确性、跳转到设备的引导扇区DBR

  • 硬盘分区表DPT:硬盘分区有很多好处。考虑到每个区可以安装不同的操作系统,MBR因此必须知道将设备控制权转交给哪个区。

  • 结束标志:若为0x55或0xAA,则该设备可以用于启动;反之则不行

  • DBR(分区引导记录):

    • JMP指令:跳转到启动代码段
    • 文件卷头
    • 启动代码:跳转到加载程序
    • 结束标志

2.VBR-Bootloader-OS

  • 硬盘启动
  • 卷引导记录VBR:哪里装着操作系统
  • 扩展分区和逻辑分区:四个分区再分,成为逻辑分区
  • 启动管理器Boot loader
    • 文件系统中读取加载程序
    • 选择操作系统内核、填入动态加载参数
    • 跳到对应内核代码段
  • 加载操作系统

中断、异常与系统调用

  • 区别:外部中断、内部异常;中断为异步、异常为同步;非CPU指令执行后产生的叫中断,CPU指令执行后产生的叫异常
  • 中断处理:

  • 硬件:设置中断标志,按中断向量表跳转到对应中断指令段的入口(进入软件阶段)

  • 软件:保存现场、执行中断指令、清除中断标志、现场恢复
  • 软件处理可能会被硬件中断打断(比如缺页中断)、被其他软件处理嵌套
  • 系统调用处理(利用中断的机制)

  • 目的:隔离用户态与内核态

  • 处理器的特权级存放在PSW中,详细状态内容存在CR3寄存器
  • 程序状态字PSW:指示处理器状态(包括状态标志、控制状态),便于保存现场
  • RISCV中的PSW实际上被分散在了各个CSR中

  • 区分缺页中断与缺页异常

  • 中断:OS请求分页的过程中缺页触发缺页中断,因为请求分页属于OS操作(非CPU指令)

  • 异常:访存时缺页触发缺页异常,因为访存指令属于CPU指令

内存管理

内存管理技术

  • 连续内存管理:分区
  • 非连续内存管理:分段(segmentation)、分页(paging)、虚拟存储(virtual memory)

逻辑地址与物理地址的转换

  • 编程或编译时确定
  • 静态重定位确定
  • 动态重定位确定

1.连续物理内存-分区

物理地址 = 逻辑地址 + 基址

  • 动态分配

  • 最先分配FFA:直接选用第一个够用的分区。

  • 最优分配BFA:空闲分区列表从小到大排序,搜索一个比它大但最小的分区,分区利用率最高。
  • 最差分配BFA:与最优策略对应,空闲分区由大到小排。
  • 它们各有优势,需注意它们之间的优点、缺点、产生碎片的区别

  • 伙伴系统分配

  • 采用二分的思路进行占用率相对较高的分配

  • 合并时注意,两段内存可以合并的条件是,它们两个对应的节点在二叉树中的父节点相同。

  • 碎片整理

  • 紧凑策略:通过移动分配给进程的内存分区,以合并外部碎片

  • 分区对换:通过抢占并回收出于等待状态进程的分区,从而增大可用内存空间。
    • 类似windows的虚拟内存机制,相等于将一部分外存用作内存,.swp文件就来源于分区对换(swapping)
    • 也是早期多进程实现方式

2.非连续物理内存-分段

  • 基本单元:
  • 按逻辑分段:主代码段,子模块代码段、公用库代码段、stack、heap、初始化数据段、符号表等
  • 目的:段式存储在做==内存保护==方面有优势。在逻辑上拆分存储内容,如果访问内容所属类别与存储内容不一致,则可以判定为“段错误”。同时,段式存储还可以实现==段中模块的共享==,即不同进程使用物理内存中的同一个段。
  • 逻辑地址与物理地址的转换:

  • MMU:内存管理单元

  • 实现逻辑地址到物理地址的映射,还可以判断是否发生段页访问的错误。

  • TLB:一个高速缓存,用于缓存页表转换的结果(快表),从而缩短页表查询的时间。
  • TWU:一个页表遍历模块,页表是由操作系统维护在物理内存中,但是页表的遍历查询是由TWU完成的,这样减少对CPU资源的消耗。

  • 段中各模块的共享(覆盖策略)

  • 必要模块:常驻
  • 可选模块:用到时装入
  • 不会同时使用的模块:相互覆盖,共用存储

3.非连续物理内存-分页

  • 基本单元:
  • 物理地址空间中的单元叫做物理页面,一般地,称为页帧(page frame),简称帧(frame)
  • 逻辑地址空间中的单元称为逻辑页面,一般地,称为页面,简称页(page)
  • 帧和页的大小必须相同。
  • 物理地址的二元组形式:
  • 有时物理地址不是写成二进制,而是写为一个二元组(f,o)。f为帧号(占s位),o为偏移。
  • 则二元组(f,o)的对应地址为$$ = f<<2^{s}+o = f\cdot2^{s}+o$$

  • 逻辑地址与物理地址的转换:

  • 设置一个页表寄存器PTR,保存内存中单一页表基址和页表长度

  • 页表

  • 每个进程都有一个页表,每一个页面都有一个页表项。

  • 页表是按照逻辑页号的顺序排列的,所以页号并不需要存入页表项。
  • 页表项中只储存物理帧号以及一些标志位。
  • 页表中的内容随着进程的运行状态而动态变化。为了表征这些变化所以引入标志位,比如存在位、修改位、引用位等(这些后续会讲到)。

  • 页表访问优化技术

  • 减少相同的多次访问请求:使用TLB(快表)

  • 页表可能非常大:间接访问(多级页表)

    • CR3与PDBR寄存器:
    • CR3寄存器:存储当前处理器的特权级
    • PTBR寄存器:上文PTR的升级版,可以存储==不同特权级下不同页表==的==基址==,便于特定特权级下的页表查询
  • 使用内存空间来减小页表大小:反置页表(但是会增加搜索时间————Hash冲突)

    • 普通映射方式是:逻辑地址--(页号)-> 页表--(帧号)->物理地址,为了实现正向映射,页表的主键是页号。但由于每个进程的页号都是分开的,所以每个进程就要设置一个页表

    • 而物理地址是共用的,如果==使用帧号来作为页表的主键==,那么所有进程就可以同时使用一个页表,称为==反置页表IPT==,这个时候就无法使用正向映射了。

    • 同时,为了使所有进程都能使用一个页表,页表项必须加入==进程的PID==作为标识

    • 为了实现映射,可以建立一个hash表减少搜索时间,key=PID与页号进行HASH,value=PID进程下页号对应的页表项。

    • IPT与PT的差别:

      • PT = 按页号索引的页表。映射时使用页号根据PT索引,在页表中查找,查找到页表项后得到帧号。

      • IPT = 按帧号索引的页表。映射时用HASH在Hash表中查找,查找到对应页表项后,根据IPT索引得到帧号。

4.非连续物理内存-段页式

  • 对每一个段进行分页
  • 不同进程的共享段就可以共用一个页表了

总结

1.分页

  • 页表存在内存中
  • 页表可以是只读的
  • 页表可以有特权级
  • 页表项标志位:驻留位(是否在内存中)、修改位(脏位)、访问位(最近被访问过)、保护位(只读/可读写/可执行等)、锁定标志位(表明为关键页,防止被换出)

2.分段

  • 段的大小可以不一致
  • 不同进程的段可以有重叠
  • 因为有共享段的存在,使得两个进程可以使用同一个段
  • 即,同一个物理内存区域可以同时映射到多个进程的内存地址空间
  • 可以有特权级
  • 段与段之间可以是不连续的

虚拟存储

已有的解决内存不够的方法:

  • 段式存储中的覆盖策略
  • 分区存储中的交换策略

1. 局部性原理

  • 时间局部性:某条指令的执行,某个数据的访问集中在较短时期内
  • 空间局部性:当前执行的几条指令、当前访问的一些数据集中在较小区域内
  • 分支局部性:一条跳转指令的两次执行,很可能跳转到相同的内存位置

也就是说,除了这些局部区域的数据必须被内存存储以外,其他数据都可以先调出到外存,需要使用时再从外存调入。

2. 虚拟存储

  • 虚存就是将外存作为虚拟的内存使用,实现时将不常用的部分内存块暂存到外存。需要使用时OS发送缺页/缺段中断
  • 实现方式:虚拟页式存储、虚拟段式存储
  • 表现:页数>=帧数(或块数),多余的页其实都存在虚存(即外存)中

虚拟页式存储

在之前的页式存储(非连续)的基础上,增加请求调页和页面置换的机制。

思路:

  • 只装必要的部分即可运行
  • 需要的代码或数据不在内存,发送缺页中断
  • 中断程序从外存调入必要页面

缺页中断的发出

缺页中断的处理

  • 在页面换入过程中,不一定有直接的空闲页面,所以我们要使用==页面置换算法==挑选其他可以调入的空闲页面。

  • 在物理内存没有空闲以换入时,4将遵循如下的步骤:

  • 依据==页面置换算法==(见下文),选择将被替换的物理帧f,对应逻辑页q(这里存在:物理帧->逻辑页的反向查找)
  • 如果q的修改位为1,则要写回外存
  • 修改q的驻留位为0
  • 将页p装入页面f

虚拟页式存储管理的性能可以用有效存储访问时间EAT来评定:

为了使引入虚拟页式存储的时间尽可能小,必须要保证缺页率p相当低。

页面置换算法

在给出页面置换的结构之前,我们有一类特例,即不被换出的页面:页面锁定(frame locking)

  • 操作系统的关键部分,描述必须常驻的逻辑页面,这部分页面对响应速度有要求

  • 利用==页表中的锁定标志位==来实现

评价方法:页面轨迹统计,模拟页面置换行为,记录缺页次数

页面置换算法分类:

  • 局部页面置换算法(选择范围仅限当前进程占用的物理页面)
  • 最优算法:全知全能,量身定制,但不可能被实现
  • 先进先出算法:先调入的页先调出
  • 最近最久未使用算法:一个统计方法,实现较麻烦
  • 时钟算法,最不常用算法
  • 全局置换算法(选择范围是所有可换出的物理页面)
  • 工作集算法
  • 缺页率算法

局部页面替换算法

1.最优页面置换算法OPT

  • 置换在未来的最长时间不访问的页面需要预测未来的使用频率,无法被实现

2.先进先出算法FIFO(节点:进入内存)

  • 选择在内存中驻留时间最长的页面进行换出。==实现:维护一个队列即可。==效果不太好,一般不用
  • Belady现象:进程分配页帧数增加时,缺页并不一定减少。
  • FIFO算法的置换特征与局部性原理不相符。
  • 与进程访问的动态特征相矛盾,被它置换出去的页面并不一定是进程近期不会访问的。

3.最近最久未使用算法LRU(节点:被使用)

  • 局部性原理表明,如某些页面长时间未被访问,则它们在将来可能会长时间不会访问。

  • 选择最长时间没有被引用的页面进行置换。==实现:维护一个优先队列(最大堆/链表结构)。缺页时,计算内存中每个逻辑页面的上一次访问时间,时间越久,换出优先级越高。==时间复杂度太大,一般不用

4.时钟算法(Clock)

  • LRU的近似,FIFO的改进

  • 思路:

  • 页初始装入时,访问位置0;被访问时,访问位置1。

  • 将一个进程在内存中的所有页面,连成一个钟表面,指针指向最老的页面(最先被装入)
  • 当发生一个缺页中断时,考察指针页面,若驻留位为1(页面在内存中)且访问位为0(视为最久未被访问的页面),立即换出该页面,同时指针后移;反之,访问位置为0(因为没有访问该页面),同时指针后移继续考察,直到换出一个页面。
  • 注:每次移动指针时都要根据是否换出页面,来更新指向该页面的访问位

5.改进的Clock算法(二次机会法)

  • 加入修改位(脏位)来帮助置换

  • 可以区分页被读还是被写

  • 被读:访问位为1,修改位为0;被写:访问位为1,修改位为1

  • 改进原因

  • 如果这个页在内存中==仅发生过读操作==,那么该页在内存中的数据==在外存中的数据,换出时可以直接扔掉,效率很高。

  • 如果这个页在内存中发生过写操作,那么该页在内存中的数据=/=在外存中的数据,换出时还需要复制到外存,效率低。

  • 二次机会法

  • clock算法中需要尽量避免换出:进行过写操作的页面

  • 当指针指向一个进行过写操作的页面(访问位0修改位1)时,需要避免换出,指针后移,同时修改位置0(下一次还要换它的话就不阻止了,即给它第二次机会)。

6.最不常用算法LFU

  • LRU的改进(不维护优先队列,只维护链表上的几个计数器)
  • 每个页面增加访问计数,访问页面时,计数+1;缺页时换出计数最小的页面。
  • LFU和LRU的区别
  • LRU:时间越久优先级越高
  • LFU:频率越少优先级越高

全局页面替换算法

工作集模型

  • 可以定量分析局部性原理的模型
  • 工作集:一个进程当前正在使用的页面集合。以$$W(t,\Delta t)$$表示。t表示当前时刻;$$\Delta t$$表示工作集窗口,即访问一个定长页面所需的时间长度;$$W(t,\Delta t)$$表示t时刻之前的$$\Delta t$$时间段中,包含的所有页面组成的集合。(设$$\Delta t$$固定,则t变化,W也会跟着变化)注意,集合包含t时间点本身
  • 工作集的模:对应的页面数目
  • 驻留集:当前时刻,进程实际驻留在内存中的页面集合。
  • 工作集与驻留集的区别:工作集是实际需要访问的页面,可能在内存中也可能不在;而驻留集一定在内存中。驻留集属于工作集。

1.工作集页面替换算法(主动换出)

  • 主动换出:不需要等到缺页时再换出,而是==每次访存时==都要换出不在工作集的页面。

  • 实现:每次访问就往工作集中加一个页面(不去重),滑动窗口前移,并将离开窗口的页面主动换出。

  • 换入不能主动换入,只能发生缺页时再换,因为我们不能预知谁会被访问到。

  • 类似于维护一个头为$$t-\Delta t$$、长度为$$\Delta t$$、尾为$$t$$的==大小固定==的滑动窗口。

2.缺页率页面替换算法PFF

  • 工作集页面替换算法的改进,需要维护一个==长度不固定==的滑动窗口,长度变化的依据是缺页率。
  • 缺页率PFR计算:$$PFR = 缺页次数/内存访问次数$$ 或者 $$PFF = 1/MTBR$$
  • MTBR:平均缺页时间间隔
  • 若缺页率高时则说明工作集太小,需要增加工作集;反之则减小工作集。
    • 工作集太大的缺点:会降低并发度,使CPU利用率下降

  • 实现:初始给一个工作集大小$$\Delta t0$$。每当缺页发生时,记录当前时间T1,并计算==上次缺页时间T0到当前T1的缺页时间间隔$$\Delta t1$$==。
  • 若缺页时间间隔大于$$\Delta t0$$,说明缺页率较低,需要减小工作集,将$$\Delta t1$$间隔外的页面移除。
  • 反之,说明缺页率较高,需要增加工作集,仅移入页面。
  • 效果:将缺页时间间隔稳定在$$\Delta t0$$左右

抖动问题(Thrashing)

  • 量化参数
  • MTBF:平均页缺失时间
  • PFST:页缺失服务时间

Thrashing

  • 最佳的点处于$$N_{I/O-Balance}$$点,即MTBF=PFST的时候,对应的CPU利用率也很高。
  • PFF算法可以做到这一点。