[toc]
- 内存空间的分配和回收
- 地址转换:逻辑地址转化为物理地址
- 内存空间的扩充:利用虚拟存储技术或自动覆盖技术,从逻辑上扩充内存
- 存储保护:保证各作业在各自的存储空间内运行,互不干扰
- 编译
- 编译程序将用户源代码编译成若干目标模块
- 链接
- 链接程序将编译后形成的一组目标模块以及所需的库函数链接在一起,形成一个完整的装入模块
- 装入
- 装入程序将装入模块装入内存运行
- 静态链接
- 在运行之前将各个目标模块以及所需的库函数链接成一个完整的可执行程序
- 装入时动态链接
- 再装入内存时,边装入边链接
- 运行时动态链接
- 在程序执行过程中需要该目标模块时才进行,便于修改和更新
- 绝对装入
- 编译程序产生绝对地址的目标代码
- 只适用于单道程序环境
- 可重定位装入
- 程序中的其他地址都是相对于始地址
- 根据内存的当前状态,将装入模块装入内存的适当位置
- 装入时对目标程序中的指令和数据的修改的过程称之为重定位
- 动态运行时装入(动态重定位)
- 地址转换推迟到真正需要执行时才进行
- 需要重定位寄存器的支持
- 可以将程序分配到不连续的存储区
- 程序运行之前可以只装入部分代码即可投入运行,运行期间动态申请分配内存
编译完成之后每个目标模块都从 0 号单元开始编址,称为该目标模块的相对地址(逻辑地址)
物理地址空间指内存中物理单元的集合
- 在 CPU 中设置一对上、下限寄存器,存放用户作业在主存中的上限和下限地址,访问地址时分别与其作比较,判断是否越界
- 采用重定位寄存器(基址寄存器)和界地址寄存器(限长寄存器),重定位寄存器含最小的物理地址值,界地址寄存器含逻辑地址的最大值
早期计算机主存容量小
程序运行时并非访问程序依据数据的各个部分,可以将用户空间分成一个固定区和若干覆盖区。经常活跃的部分放在固定区,其余部分按调用关系分段,首先将即将访问的段放入覆盖区,其他放在外存中,需要调用前将其调入覆盖区
- 打破了一个进程的全部信息装入主存后才能运行的限制
- 当同时运行程序的代码量大于主存时仍不能运行
- 只能更新覆盖区的段,不在覆盖区的段会常驻内存
- 换出:把处于等待状态的程序从内存移到辅存,把内存空间腾出来
- 换入:把准备好竞争 CPU 运行的程序从辅存移到内存
- 交换需要备份存储,通常是快速磁盘,必须足够大,提供对内存映像的直接访问
- 为了有效使用 CPU,要使每个进程执行的时间比交换的时间长
- 换出的进程序确保处于空闲状态
- 交换空间通常作为磁盘的一整块,独立于系统文件(使用起来很快)
- 减缓通常在许多进程运行且内存吃紧时开始启动,系统负荷降低时暂停
内存分为系统区和用户区,无需进行内存保护,因为内存中只有一道程序
- 优点:简单,无外部碎片,可以采用覆盖技术,无需额外的技术支持
- 缺点:只能用于单用户、单任务操作系统,有内部碎片,存储器利用率低
将用户分区空间划分为若干固定大小的区域,每个分区只能装入一道作业,当有空闲分区的时候,从外存的后备队列中选择适当大小的作业装入该分区
- 大小分区相等:用于一台计算机控制多个相同对象的场合,缺乏灵活性
- 分区大小不相等:划分为多个较小的分区、适量的中等分区、少量大分区
- 程序可能太大放不进任何一个分区
- 内存利用率低,存在内部碎片
在进程装入内存时,根据进程的大小动态的建立分区,使分区的大小刚好适合进程的需要
- 存在外部碎片的问题,可以通过紧凑技术解决,但需要动态重定位寄存器的支持,相对费时
- 首次适应算法:空闲分区按地址递增
- 最佳适应算法:空闲分区按容量递增
- 最坏适应算法:空闲分区按容量递减
- 邻近适应算法:从上一次查找结束的位置继续查找
作业道数 | 内部碎片 | 外部碎片 | 硬件支持 | 可用空间管理 | 解决碎片方法 | 解决空间不足 | 提高作业数 | |
---|---|---|---|---|---|---|---|---|
单道连续分配 | 1 | 有 | 无 | 界地址寄存器、越界检查机构 | 覆盖 | 交换 | ||
多道连续分配 | $\leq$N | 有 | 无 | |||||
多道可变连续分配 | 无 | 有 | 数组、链表 | 紧凑 |
允许有个程序分散装入不相邻的内存分区
主存空间划分为大小相等且固定的块,块相对较小,作为主存的基本单位。 每个进程也以块为单位划分,进程在执行的时候,以块为单位逐个申请主存中的块空间
- 不会产生外部碎片
- 产生内部碎片相对较小(为最后一个不完整的块申请主存块空间才产生)
- 页面和页面大小
- 进程中的块称为页,内存中华的块称为页框,外存以同样的单位划分,称为块
- 页面大小是 2 的整数幂,大小应该适中
- 地址结构
31...12 11...0 页号 p 页内偏移量 w - 页表
- 记录页面内存中对应的物理块号,一般存放在内存中
- 页表由页表项构成,第一项为页号,第二项为物理内存中的块号
- 页表项的第二部分与地址项的第二部分共同组成物理地址
任务: 将逻辑地址转换为内存中的物理地址,借助页表实现 设置一个页表寄存器,存放页表在内存的起始地址 F 和页表长度 M 设页面大小为 L,逻辑地址 A 到物理地址 E 的 变换过程如下:
- 计算页号
$P=A/L$ ,页内偏移量$W=A%L$ - 比较页号
$P$ 和页表长度$M$ 。若$P≥M$ ,则产生越界中断,否则继续执行 - 页表中页号 P 对应的页表项地址=页表始址 F + 页号 P x 页表项长度,取出页表项内容 b,即为物理块号
- 计算 E=b x L + W,用得到的物理地址 E 访问内存
- 地址转换必须足够快,否则访存速度低
- 页表不能太大,否则内存利用率低
页表全部存放在内存中,存取数据或指令至少需要两次访问内存:
- 访问页表,确定物理地址
- 根据该地址存取数据或指令
快表(相联存储器):存放当前访问的若干页表项,加速地址变换过程:
- CPU 给出逻辑地址后,硬件进行地址转换,将页号送入高速缓存寄存器,将页号与快表中的所有页号比较
- 找到匹配的页号,直接从中取出该页对应的页框号,与页内偏移量拼接形成物理地址
- 若未找到,需要访问主存中的页表,读出页表项之后同时将其存入快表,若快表已满则按照一定算法替换
考虑了用户和程序员,满足方便编程、信息保护和共享、动态增长、动态链接等多方面需要
按照用户进程中的自然段划分逻辑空间,每段分配一段连续的地址空间
地址空间:
31 ... 16 | 15 ... 0 |
---|---|
段号 S | 段内偏移量 |
- 页式系统中,页号和页内偏移量对用户透明
- 段式系统中,段号和段内偏移量由用户显式提供,高级语言由编译程序完成
段号 | 段长 | 本段在主存中的始址 |
---|
设置段表寄存器,存放段表始址 F 和段表长度 M,逻辑地址 A 到物理地址 E 之间的地址变换过程如下:
- 从逻辑地址 A 中取出前几位为段号 S,后几位为段内偏移量 W
- 比较段号S和段表长度 M,若 S
$\geq$ M,则产生越界中断,否则继续执行 - 段表中段号 S 对应的段表项地址=段表始址 F+ 段号 S x 段表项长度,取出该段表项的前几位为段长 C,若偏移量
$\geq$ C,则产生越界中断 - 取出段表项中该段始址 b,E = b + W ,访问内存 E 的地址
作业的地址空间首先被分为若干逻辑段,每段有自己的段号,然后将段分为若干大小固定的页
逻辑地址结构:
段号 S | 页号 P | 页内偏移量 W |
---|
为了实现地址变换,每个进程建立一张段表,每个分段有一张页表
段表表项: 段号 + 页表长度 + 页表始址
页表表项:
页号 + 块号
系统中含有一个段表寄存器,指出作业的段表始址和段表长度
- 一次性
- 作业很大不能全部装入内存时,改作业无法运行
- 大量作业要求运行时,内存不足以容纳所有作业
- 驻留性
- 作业被装入内存后,一直驻留在内存中
- 时间局部性
- 空间局部性
- 多次性: 作业运行允许分成多次调入内存运行
- 对换性 允许作业在运行过程中,进行换进和换出
- 虚拟性 从逻辑上扩充内存的容量,使用户所看到的内存容量远大于实际的内存容量
- 请求分页存储管理
- 请求分段存储管理
- 请求段页式存储管理
- 一定容量的内存和外存
- 页表机制(段表机制)作为主要的数据结构
- 中断机构
- 地址变换机构
页表项:
页号 | 物理块号 | 状态位 P | 访问字段 A | 修改位 M | 外存地址 |
---|
增加的字段说明:
- 状态位 P:指示该页是否已调入内存
- 访问字段 A 记录本页在一段时间内被访问过的次数
- 修改位 M:标识该页在调入内存之后是否被修改过
- 外存地址:指出该页在外存上的地址,通常是物理块号
每当访问的页面不存在内存中时,便产生一个缺页中断,请求操作系统将所缺失的页调入内存,此时将缺页的进程阻塞
- 指令执行期间产生和处理中断信号,属于内部中断
- 一条指令执行期间可能会产生多次缺页中断
在地址变换时,先检索快表
- 若找到要访问的页,则修改页表项的访问位,利用页表项中给出的物理块号和页内地址形成物理地址
- 若未找到页表项,则去内存中查找页表,对比页表项的状态位 P,看是否已调入内存,未调入会产生缺页中断
淘汰以后永不使用的页面,或者最长时间内不被访问的页面,以便保证获得最低的缺页率
- 算法无法实现
优先淘汰最早进入内存的页面
选择最近最长时间未访问过的页面予以淘汰,为每个页面设置一个访问字段,记录页面自上次被访问所经历的时间
每帧附加一个使用位,0 表示最近未被修改和访问,1 相反
时钟置换算法会多遍扫描环形队列。
- 第一遍:优先寻找修改位和访问位都为0
- 第二遍:若第一遍未寻找到,则继续扫描,扫描过的节点置访问位为0,并寻找放低标准寻找未访问的修改过的页。
- 若找到,结束;未找到,重复1,2
再增加一个修改位
- 最近未被访问,也未被修改(u=0,m=0)
- 最近被访问,但未被修改(u=1,m=0)
- 最近未被访问,但被修改(u=0,m=1)
- 最近被访问,被修改(u=1,m=1)
算法过程:
- 从当前位置开始,对使用位不修改,选择第一个帧(u=0,m=0)用于替换
- 若1 失败,重新扫描,查找(u=0,m=1)的帧用于替换
- 若 2 失败,回到最初位置,且集合中所有帧的使用位均为 0,重复上两步
进程在准备执行时,不需要也不可能把一个进程所有页读入主存,因此操作系统决定给特定的进程分配几个页框,物理页框的集合就是这个进程的驻留集。需要考虑一下几点:
- 分配给一个进程的存储量越小,任何时候驻留主存的进程数量越多,可以提高处理机的时间利用率
- 若一个进程在主存的页数过小,页错误率依然会很高
- 若页数过多,给特定的进程分配更多的主存空间对该进程的错误率没有明显影响
- 固定分配局部置换
为每个进程分配一定数目的物理块
- 难以确定每个进程分配的物理块数目
- 可变分配全局置换
为系统每个进程分配一定数目的物理块,操作系统自身页保持一个空闲物理块队列。当某进程发生缺页,系统从空闲物理快队列中取出一个物理块分配给该进程
- 会盲目给进程增加物理块,导致并发能力下降
- 可变分配局部置换 为每个进程分配一定数量的物理块,某个进程发生缺页时允许从该进程在内存的页面选出一页换出,若进程平凡缺页,则系统再为进程分配若干物理块;若缺页率特别低,则适当减少分配给进程的物理块
- 预调页策略 采用以预测为基础的预调页策略
- 请求调页策略 进程运行中需要访问的页面不在内存而提出请求,由系统将所需页面调入内存
- 系统拥有足够的对换区空间 从对换区调入所需页面
- 系统缺少足够的对换区空间
- 不会被修改的文件:直接从文件区调入,换出时,由于未被修改而不必将它们换出
- 可能会被修改的文件:换厨师调到对换区,以后需要时再从对换区调入
- UNIX 方式
- 进程相关的文件放在文件区,未运行过的页面都从文件区调入
- 曾经运行过党又被换出的页面,下次调入从对换区调入
刚刚换出的页面马上又要换入主存,刚刚换入的页面马上又要换出主存
发生抖动的原因:某个进程频繁访问页面数目高于可用的物理页帧数目