这一节从程序装载、运行的角度来简单描述一下内存的活动。内存是用于存放数据的硬件,按字或字节顺序编址,由于CPU的处理速度远远高于硬盘的读取速度,故程序执行前需要先存放到内存中才能被CPU处理,这一过程涉及到程序的装载,程序被加载到内存后,由于CPU处理速度和内存读取速度仍然存在巨大差异,故仍需要更高速的存取设备作为缓冲区,即缓存,这一过程涉及到程序的运行。
程序从原码到执行的整个过程:原码->编译->链接->装载->运行
- 装载方式:
- 绝对装入:在原码经过链接后即可确定模块的物理地址;
注:只适用于单道程序环境。
链接阶段确定物理地址。
- 静态重定位:编译、链接后的装载模块的地址都是从0开始的,指令中使用的地址、数据存放的地址都是相对于装载模块的起始地址而言的逻辑地址,装载时需要对地址进行重定位,将逻辑地址变换为物理地址;
注:静态重定位方式必须一次性将程序所有模块加载到内存当中,因为程序一旦装载到内存中后,运行期间就不能再移动,也不能在申请内存空间。
装载阶段确定物理地址。
- 动态重定位:编译、链接后生成的装载模块地址都是从0开始的,装入程序将模块装载到内存后,并不会立即把逻辑地址转换为物理地址,而是当程序运行时才会根据重定位寄存器的值确定数据的存放地址;
注:需要硬件 重定位寄存器 配合使用。
运行阶段确定物理地址。
- 绝对装入:在原码经过链接后即可确定模块的物理地址;
- 内存分配与回收
- 分配:内存被分为系统区(低地址)和用户区(高地址);
- 连续分配
- 单一连续分配:内存中只能存在一个用户程序,用户程序独占整个用户区。
- 固定分区分配:需要建立分区说明表,每个表项对应一个分区,通常按分区大小排列,表项包括对应分区的大小、起始地址、状态信息;
- 分区大小相等;
- 分区大小不相等。
- 动态分区分配:不会预先划分内存,在程序装载到内存时,根据程序的大小动态的建立分区,分区大小刚好适合程序需要,因此分区大小和数目是可变的,同样需要建立分区表或者分区链。
- 首次适应(First Fit)
- 最佳适应(Best Fit)
- 最差适应(Worst Fit)
- 邻近适应(Next Fit)
- 离散分配:
- 分页存储:操作系统会将内存的用户区域分成大小相等的分区,每个分区为一个页框(内存块),每个分区按照顺序从0开始编号,称为页框号(块号)。
- 页表寄存器:页表在内存中的起始位置F&页表长度M;
- 进程控制块(PCB):程序未运行时起始位置F&页表长度M的存放位置;
- 页表(慢表):操作系统为每个进程创建一张页表,页表中存放了多个页表项,每个页表项中存放了当前内存块号;
- 快表(TLB):是一种访问速度比内存快很多的高速缓冲存储器,用来存放当前访问的页表项,加速地址的变换过程;
- 地址变换:
- 程序计数器PC中读取程序的逻辑地址;
- 判断逻辑地址页号是否越界;
- 查询快表是否命中当前页号,确定内存块号,合并页内偏移量,生成物理地址;
- 未命中,查询快表,确定内存块号,合并页内偏移量,生成物理地址。
- 多级页表:多级页表各级页表的大小不能超过一个页面,N级页表的访存次数(无快表机构) = N+1。
- 分段存储:进程按照自身的逻辑关系将自身的内存空间划分为若干个段,每个段都有一个段名(低级语言中程序员用段名来编程),每个段从0开始编程;
- 内存分配原则:以段为单位进行分配,每个段在内存中占据连续空间,各段之间可以不相邻;
- 分段存储逻辑地址格式:
- 段表项格式:
- 地址变换:分段存储的逻辑地址转为物理地址的过程与分页存储大致相同,不同点在页表中的页表项与段表中的段表项内容有所不同,每个页框(物理块)的大小是相同的,所以在页表项中不需要保存每个页表的长度;在分段存储的情况下,每个段的长度都不相同,故段表项中需要保存段长信息,并检查基址+段长是否越界;
- 内存分配原则:以段为单位进行分配,每个段在内存中占据连续空间,各段之间可以不相邻;
- 段页存储:
注:段页式内存管理方式发生缺页现象时需三次访存,1.访问段表;2.访问页表;3访问目标内存地址。
- 分段、分页管理对比:
- 段页存储的逻辑地址结构:
- 地址变换:与分页是存储地址变换过程大致相同;
- 分页存储:操作系统会将内存的用户区域分成大小相等的分区,每个分区为一个页框(内存块),每个分区按照顺序从0开始编号,称为页框号(块号)。
- 连续分配
- 回收:内存的回收原则就是相邻的空闲内存需要合并。
- 内部碎片:程序(进程)所在的内存空间无法利用的空闲区域;
- 外部碎片:在内存中,程序(进程)间过小的内存块不能满足新进程对于内存的需求而产生的无法利用的内存区域。
- 分配:内存被分为系统区(低地址)和用户区(高地址);
- 内存空间的扩充
- 覆盖技术(已弃用):按照程序的逻辑结构,使不可能同时被访问的程序段共享一块内存区域(覆盖区);
- 交换技术:内存空间紧张时,系统将某些程序(进程)暂时换出外存,将需要处理的程序加载进内存;
注:程序的PCB常驻内存的系统存储区域。
- 对换区:外存一般分为两个区域:
- 对换区:换出内存进程的存放区,追求读写速度,采取连续分配的方式;
- 文件区:用于存放文件,追求存储空间的利用率,采取离散分配的方式。
- 换出时机:内存紧张,表现为缺页严重;
- 优先换出阻塞进程。
- 对换区:外存一般分为两个区域:
- 虚拟内存:·程序装载时,操作系统可将程序中待执行的部分装载到内存中,其他部分暂时驻留外存;·程序运行过程中,当所访问的程序段不在内存中时,由操作系统负责将所需信息从外存调入内存,程序继续运行;·内存空间不足时,再由操作系统负责将内存中暂时用不到的信息换出到外存;·操作系统的调度下,用户看起来内存似乎看起来要大的多,这就是虚拟内存。
注:操作系统虚拟性的体现:实际物理内存大小未变,逻辑上进行了扩充。
虚拟内存最大容量 == CPU寻址范围
虚拟内存的实际容量 == min(CPU寻址范围,内存+外存)
- 局部性原理
- 时间局部性:程序在一段时间内多次执行某个指令;
- 空间局部性:程序在执行过程中多次调用某个数据;
- 高速缓存原理:将近期会频繁访问的指令或者数据存储到更高速的存储介质中,提高程序执行速度;
- 页(段)面置换
- 页表:状态位:页是否在内存中,访问字段:最近访问次数
- 缺页(段)中断机构:当前指令想要访问的目标页(段)面未调入内存所引起的中断称为缺(段)页中断。
- 缺页(段)的进程阻塞,调入页(段)面后将其唤醒,放入就绪队列;
- 内存中存在空闲块,则为进程分配一个空闲块装载所缺页面;
- 内存中不存在空闲块,则由页(段)面置换算法选择淘汰一个页(段)面,若淘汰页(段)面在内存期间被修改,则需写回外存。
- 请求分页管理地址变换:
- 请求分页置换算法:页面的换入、换出需要磁盘IO,造成较大开销,故应采用缺页率较少的算法。
- 最佳置换算法(OPT):每次选择淘汰的页面将永不使用,或最长时间不使用,该算法可以保证最佳的缺页率,但实际上操作系统无法提前预判页面访问序列,因此,该算法无法实现;
- 先进先出置换算法(FIFO):每次淘汰最早进入内存页面,该算法实现简单,但会出现Belady异常现象---为进程分配的内存页面增加时,缺页率不降反增,因为先进入的页面也有可能被频繁访问,算法性能较差;
- 最近最久未使用置换算法(LRU):每次淘汰最久未使用页面,该算法性能好,但实现困难,需要逆向查询最久未使用页面,需要特定的硬件支持,开销较大;
- 时钟置换算法(CLOCK,NRU):内存中的页面使用指针组成循环队列,并对每个页面设置访问位,每次访问后将访问位设置为1,否则为0,每次淘汰页面时检查访问位,if 访问位==0,直接换出页面,else if 访问位==1,将访问位置0,循环检查,最多循环两次;
- 改进型的时钟置换算法 :在时钟置换算法的基础上检查页面是否被修改,在条件相同的情况下,优先置换没有修改过的页面,使用(访问位,修改位)标识页面;
- 第一轮:扫描第一个(0,0)替换,不修改标志位;
- 第二轮:扫描第一个(0,1)替换,修改访问位为0;
- 第三轮:扫描第一个(0,0)替换,不修改标志位;
- 第四轮:扫描第一个(0,1)替换;
- 页面分配策略:
- 驻留集:请求分页存储中进程所分配的物理块的集合;
注:1.驻留集过小:缺页频繁,伴随大量的IO操作;2.驻留集过大:浪费资源。故驻留集大小应当合适,采用虚拟内存技术的系统中,驻留集一般小于进程的总大小。
- 分配策略:
- 固定分配:操作系统为进程分配物理块后大小不再改变;
- 可变分配:操作系统首先为进程分配一定数目的内存块,之后根据情况调整进程物理块的数量。
- 置换策略:
- 全局置换:可将内存中空闲块分配给缺页进程,也可以将其他进程物理块换入外存后分配给缺页进程;
- 局部置换:只能选择进程自己的物理块进行置换。
- 分配策略:
- 工作集:某段时间内进程实际访问的页面集合。
- 调入页面时机:
- 预调页策略:运行前调入固定数目的页面,如main函数所在页面;
- 请求调页方式:运行期间才将缺页调入内存。
- 调入页面位置:
- 对换区存在空闲:页面调入、调出都在对换区,程序运行前需要将数据从文件区复制到对换区;
- 对换区不存在空闲:直接从文件区调入,存在修改的页面调出时存入对换区,不存在修改的区域不需要调出;
- UNIX方式:直接从文件区调入,调出时存放对换区。
- 驻留集:请求分页存储中进程所分配的物理块的集合;
- 局部性原理
- 内存保护:保证程序(进程)在自己内存空间内运行,不会越界访问。