王道考研复习-操作系统-内存管理(三)
问题思考
- 为什么进行内存管理
- 页式管理中每个页表项大小的下限如何决定
- 多级页面解决了什么问题,带来了什么问题
内存管理的基本原理和要求
- 英文:(Memory Management), 计算机硬件尽管很大,但依然不能一次将所有用户的进程和系统所需要的程序全部装入主存(通常称 16G,8G内存指的就是这个主存,他比硬盘速度快,便于程序的的调度),因此操作系统必须对内存空间进行合理的划分和有效的动态分配,这就是操作系统的概念
- 有效的内存管理在多道程序设计上非常重要,他不仅可以方便用户使用存储器,提高内存利用率,还可以通过虚拟技术来扩充存储器
内存管理的主要功能有
- 内存空间的分配与回收: 由操作系统完成主存储器空间的分配和管理,使程序员摆脱存储分配的麻烦,提高编程效率
- 地址转换: 在多道程序环境下,程序中的逻辑地址与内存中的物理地址不可能一致,因此存储地址必须提供地址变换功能,把相应的逻辑地址变换为物理地址
- 内存空间的扩充: 利用虚拟存储技术或自动覆盖技术,从逻辑上扩充内存
- 存储保护: 保证各道作业在各自的存储空间内运行,互不干扰
程序的装入和接入
- 编译: 由编译程序将用户的源代码编译称若干目标模块
- 链接: 由链接程序将编译后形成的一组目标模块及其所需的库函数链接在一起,形成一个完整的装入模块
- 装入: 由装入程序将装入模块装入内存运行
可以类比做菜的过程
将菜炒熟(编译)-> 将多道加工熟的食材组合道一起(链接) -> 盛出装入道碗中(装入)
程序的链接方式
- 静态链接: 在程序运行之前,先将各模块和目标以及它们所需要的库函数链接成一个完成的可以执行程序(如系统内置的一些硬件程序,为了提高读写效率,装入到内存提高读写效率)
- 装入时动态链接: 将用户源程序编译后所得到的一组目标模块,在装入内存时,采用边装入边链接的方式(如启动时加载的动态库)
- 运行时动态链接: 在程序执行中需要改模块时菜进行的,比如 framework的懒加载过程,适合调试用,减少调用时间(代码实现流程复杂,库依赖关系不好把控,类比iOS 动态库懒加载)
程序装入内存的实现方式
- 绝对装入: 在编译时就已经知道程序将驻留在内存的某个位置,如早起的单道处理系统,编译时产生程序绝对地址目标代码,通常情况下采用的是符号地址,编译或者汇编时候再转化为绝对地址 (事先知道地址)
- 可重定位装入: 在多道程序环境下,多个模块的起始地址通常都是从0开始,根据装入内存的开始地址加上程序地址的偏移量,将程序装入内存. 地址的变换通常是一次装入完成的,也称作为静态重定位
(考点: 一次装入,静态,装入后不可改变,根据当前内存情况,装入适当的位置) - 动态运行时装入: 也成为动态重定位, 程序在内存中若发生移动,则需要采用动态装入的方式,装入程序把装入模块装入内存后,并不立即把装入模块的相对地址转换为绝对地址,而是把这种地址推迟到程序真正要执行的时候菜进行 (不是地址转换为绝对地址,需要重定位寄存器)
逻辑地址空间与物理地址空间
- 编译后每个目标模块都是从0号单元开始编址, 成为该目标模块的逻辑地址或相对地址
- 当链接程序将各个模块链接成一个完成可执行的目标程序时,链接程序依次按各个模块的相对地址构成同意的从0号单元开始变址的逻辑地址空间
- 用户和程序猿只需要知道逻辑地址,不同的进程可以有相同的逻辑地址,这些相同的逻辑地址可以映射到主存的不同位置
- 物理地址空间: 内存中物理单元的集合,它是地址转换的最终地址。进程在运行执行指令和访问数据,最后都要通过物理内存从主存中存取。当装入程序将可执行代码装入内存时,必须通过地址转换将逻辑地址转换为物理地址,这个过程称为地址重定位。
内存保护
- 内存分配前,需要保护操作系统不受用户进程影响,同时保护用户进程不受其他用户进程的影响,内存保护可采取两种方法
- 在CPU中设置一对
上
,下
限寄存器,存放用户作业在主存中的下限和上限地址,每当CPU要访问一个地址时,分别和两个寄存器的值进行相比,判断是否有越界 - 采用重定位寄存器(或基地址寄存器)和界地址寄存器(又称限长寄存器), 重定位寄存器含有最好的物理地址, 界地址寄存器含有逻辑地址最大值, 通过他们的之间的关系就能清除的知道是否越界
- 在CPU中设置一对
- 内存分配前,需要保护操作系统不受用户进程影响,同时保护用户进程不受其他用户进程的影响,内存保护可采取两种方法
内存的覆盖与交换技术
- 覆盖:
- 特点: 打破了必须将进程的信息全部装入内存菜能执行的限制
- 实现: 将用户空间分为若干固定区和覆盖区,活跃部分放在固定区,其余部分按照调用关系分段, 首相将需要访问的段放入覆盖区域,其他段放在外存中,在需要调用前,系统将其调入覆盖区,替换覆盖区中原有的段
交换:
- 把处于等待状态的(或者CPU调度原则下被剥夺运行权利)的程序从内存移动到辅存,把内存空间腾出来,这一过程叫做换出; 把准备好竞争CPU运行的程序从辅存转移到内存中,换入.
交换需要注意的问题:
- 需要备份存储,通常是快速磁盘,必须足够大,提供对这些内存映像的直接访问
- 为了有效使用CPU,需要保证进程执行时间比交换时间长,不然就频繁交换,得不到提升,影响交换时间主要是转移时间,它们是正比关系
- 唤出进程时需要保证该进程处于完全空闲状态
- 交换空间通常为磁盘的一整块, 且独立于文件系统(交换区),使用起来很快
- 交换通常在系统有很多程序运行并且系统内存吃紧的时候执行,在系统负荷降低时就暂停
- 普通的交换使用的不多, 但交换策略的某些变体在许多系统(UNIX系统)中仍发挥作用
区别:
- 交换主要在不同的进程或作业之间
- 覆盖则在同一个程序或进程中, 由于覆盖技术要求给出程序段之间的覆盖结构,对用户和程序猿不够透明,覆盖已经成为历史,现代操作系统主要通过虚拟技术来解决问题,扩充内存,交换技术也被广泛使用。
- 关键字理解: 透明性, 适用时间
内存的连续分配管理方式
- 单一连续分配
- 内存中永远只有一道程序,独占内存,不用保护,
- 无外部碎片,
- 可以采用覆盖技术
- 只适用于单用户,单任务的操作系统,有内部碎片,存储的利用率极低
- 固定分区分配
- 简单的多道程序存储管理方式,将用户空间划分为若干固定大小的作区间
- 无外部碎片
- 但不能实现多进程共享一个主存区
- 很少用于现代操作系统中,在某些用于控制多个对象的控制系统中仍然发挥者一定的作用
(如: 同步并发执行10000个一摸一项的个程序,执行某项任务,如挖矿, 相同的程序,相同的功能)
- 动态分区分配:
- 不预先划分内存,而是进程装入内存时候,根据进程的大小动态的建立分区, 并使分区的大小正好合适进程的需要,
- 系统中的分区属木大小都是可变的
- 随着装入的程序越来越多,内存中会出现越来越多的小的内存块,形成外部碎片
- 刚开始挺好的,越到后面越来越多的碎片
- 在进程装入或换入主存时,若内存中有多个足够大的空闲块,则操作系统必须确定分配那个内存块给进程使用,者就是动态分区的分配策略
- 首次适应(First Fit): 空闲分区以递增的次序链接, 分配内存时按顺序查找,找到能满足要求的第一个空闲空间。 ( 地址递增 顺序查找找第一个能装下的空间)
- 最佳适应(Best Fit): 空闲分区按照容量递增的方式形成分区链, 找到第一个能够满足要求的空闲分区
- 最坏适应(Worst Fit): 又称为最大适应(Largest Fit),空闲分区以容量递减的次序链接,找到第一个能满足要求的空闲区间,即挑出最大分区
- 临近适应(Next Fit): 循环首次适应算法, 再首次算法的基础上开始, (第二次装入程序查找空闲分区的起始位置不同而已)
关键点: 对应了 数组顺序查询,链表头开始查询, 链表尾开始查询, 环形链表一次查询
内存非连续分配管理方式
基本的分野存储管理方式
- 内存块细分,减少碎片
- 进程也以块细分,以最小块为单位,逐个像系统申请主存中的块空间
- 如此,每个进程只会产生大概半个页的碎片
分页的概念
- 进程中的块称为页(Page)
- 内存中的块称为叶匡(Page Frame),页帧
- 外存也以同样的单位进行划分,直接称为块(Block)
- 进程在执行的时候需要申请主存空间,为每个页面分配主存中可用的页框,产生了页和页框的一一对应关系
- 页面大小为2个整数倍,保持大小适度,过小导致换入换出频繁,过大容易出现碎片,如macOS下通过pageSize可以查看操作系统的分页为4kB
dart pageSize
xxxMacBook:~ xxx$ pageSize
4096 - 地址结构
- 页号(31-12)-页内偏移量(11-0), 4字节,32位
页表
- 记录内存中页面对应的物理块号,一表一般存储于内存中,系统为每个进程创建了一个页表,记录它们在内存中对应的物理块号
页号 块号 1 2 2 3 ... ...
基本的地址变换机构
- 地址的变换机构的任务是将逻辑地址转换为内存中的物理地址,地址变换借助于页表来实现
- 系统中通常会设置一个页表寄存器(PTR, Page Table Register),存放页表在内存起始地址F和页表长度M
- 通过起始地址,页号和相对地址很容易计算出 程序中某条相对指令地址在物理地址中绝对地址
分页管理的问题
- 每次访问存储操作都需要从逻辑地址到物理地址的转换, 地址转换必须足够快
- 每个进程引入页表,用于存储进程的内存映射机制,页表不能太大
具有快表地址变换机构
- 通过上面的地址变化过程可知,若页表全部放入内存中,则存取一个数据或一条指令至少需要访问两次内存,第一次是访问页表,第二区定所存储数据或者指令的物理地址,第二次是根据该地址存取数据或指令,这种方式比普通的执行指令减慢了一半
- 为此,在地址变换机构中增设一个具有并行查找能力的告诉缓冲存储器---快表,又称为相联存储器(TLB),用来存储当前访问的若干页表项,以加速地址变换过程.与此对应,主存中的页表项常称为慢表.
快表的实现:
在具有快表分页机制中,地址的变换过程如下- CPU给出地址逻辑之后, 由硬件地址进行地址转换, 将也好送入告诉缓冲存储器,并将此页号与快表中的所有也号进行比较
- 若找到匹配的页号,说明需要访问的页表项在快表中,则直接从中取出对应的页框号,与页内偏移量拼接形成物理地址.
- 若未找到匹配的页号, 则需要访问主存中的页表,在读取页表以后,同时将其存入到快表中,以便以后能快速访问, 若快表已满,则需要按照一定的规则和算法对旧的页表项进行替换。 (一般快表的命中率达90%以上,这样分页带来的损失就可以下降到10%以下)
两级页表
- 由于引入了分页管理,进程在执行时不需要将所有页调入内存页框,只需要将保存有映射关系的页表调入内存,但仍需要考虑页表的大小 *****
为了压缩页表项,我们进一步延伸页表映射的思想,就可以得到二级分页。
一级页号 二级页号 页内偏移量
基于分段存储管理方式
- 分页的管理方式是从计算机角度来考虑设计的,提高计算器的利用率和性能,分页通过硬件机制实现,对用户完全透明,
- 分段管理方式则是考虑了用户和程序猿,以满足编程,信号保护和共享,动态增长和动态链接等多方面的需要(segment)
分段
- 段的管理方式按照用户进程中的自然段划分逻辑空间,例如用户进程由主程序,两个子程序,栈和一段数据组成,于是可以把这个用户进程划分为5段, 每段从0开始编址,并分配一段连续的地址空间(段内要求连续,段间不要求连续,因此整个作业的地址空间是二位的),其逻辑地址由段号S与段内偏移量W组成. 216 = 65536, 一个作业最多有这么多段, 由编译程序完成
|31 .... 16 | 15 ... 0 |
|------|------|
| 段号 | 段内偏移量 |
- 段的管理方式按照用户进程中的自然段划分逻辑空间,例如用户进程由主程序,两个子程序,栈和一段数据组成,于是可以把这个用户进程划分为5段, 每段从0开始编址,并分配一段连续的地址空间(段内要求连续,段间不要求连续,因此整个作业的地址空间是二位的),其逻辑地址由段号S与段内偏移量W组成. 216 = 65536, 一个作业最多有这么多段, 由编译程序完成
段表
- 每个进程都有一张逻辑空间与内存空间映射的段表,其中每个段表项对应进程的一段,段表记录该段在内存中的始址和长度,段表的内容如下
|段号|段长|本段主存的始址|
|---|---|---|
段表也是用来实现从逻辑段到物理内存区的映射 - 地址变化机构
- 同样的在系统中也设置了段表的寄存器,用来存放段的起始位置F和段表长度M
- 每个进程都有一张逻辑空间与内存空间映射的段表,其中每个段表项对应进程的一段,段表记录该段在内存中的始址和长度,段表的内容如下
段的共享和保护
- 通过两个作业的段表中相应的表项只想共享的段的痛一个物理副本中的数据。
- 与分页类似: 通过存取控制保护, 地址越界保护
- 与页式管理不同,段式管理不能够通过给出一个整数便确定对应的物理地址,因为每段的长度不是固定的
段页的管理
段号 -> 页号 -> 页内偏移量 **** 补充
虚拟内存管理
- 传统的内存管理基本概念
- 一次性
- 驻留性
- 局部性原理
- 快表,页高速缓存及虚拟内存技术从广义上讲,都属于高速缓冲技术,这个技术依赖于 局部性原理.
- 时间局部性: 存储将要执行的指令,如循环,
- 空间局不性: 如数组,顺序保存数据, 保存到高速缓冲器中
- 虚拟存储器的定义和特征
- 多次性 分多次调入内存
- 对换性 换入换出,不用常驻
- 虚拟性 内存容量远大于实际的内存容量
虚拟内存技术的实现
- 虚拟内存的实现建立在离散分配的内存管理方式基础上
- 请求分页存储管理
- 请求分段存储管理
- 请求段页存储管理
- 一定容量的内存和外存
- 页表机制
- 中断机构 (用户要访问的数据未调入内存时,则产生中断)
- 地址变换机构 逻辑地址到物理地址转换
- 虚拟内存的实现建立在离散分配的内存管理方式基础上
请求分页管理方式
- 页表机制
|页号| 物理块号| 状态位置P| 访问字段A | 修改位M |外存地址|
|--- | --- | --- | --- |---| ---| - 状态位: 用于指示该页是否已调入内存
- 访问字段A: 用于记录该页面在一段时间内被访问的次数
- 修改位M: 标示该页在调入内存后是否修改过
- 外存地址: 用于指出改页在外存上的地址,通常是物理块号,供调入时参考
- 页表机制
缺页中断机构
- 在指令执行期间而非一条指令执行完成后产生和处理中断信号属于内部中断
- 在一条指令缺失过程中,可能会产生多次的缺页中断
地址变化机构
- 若找到要访问的页,则修改页表像中的访问位,然后利用页表给出的物理块号和页内地址形成的物理地址
- 若未找到改页的页表项,则应到内存中查找页表,再比较页表项中的状态位P,若未调入内存则产生缺页中断,调入内存
页面置换算法
- 最佳置换算法(OPT): Optimal,淘汰以后永不使用或者最长时间不被访问
- FIFO: 先进先出,不够灵活,缺页故障更明显 bug
- LRU: 最近最久未使用
- CLOCK: 时钟算法, 时钟循环检查, 标志位,是否写入,优先淘汰未写入,未访问的 -> (1,1) -> ..
页面分配策略
- 驻留集大小:
- 分配给一个进程的存储量越小,任何时候驻留在主存中的进程数就越多,从而可以提高处理机时间利用效率
- 若一个进程在主存中的页数过小,则尽管有局部性原理,页错误率依然很高
- 若页数过多,则由于局不性原理,给特定进程分配更多的主存空间对该进程的错误率并没有明显的影响
- 三种分配策略
- 固定分配局部置换: 分配固定数目的物理块,若缺页,则从该进程所在的内存页面中选出一页置换
- 固定分配全局置换: 同上,从操作系统的物理块队列中取出一个物理块分配给该进程, 若盲目添加也会带来弊端
- 可变换局部置换: 分配初始的进程块,当缺页时先从该进程中置换,若一段时间缺页率高,由系统分配新的物理块,反之则回收部分物理块
- 调入页面的时机
- 预调入: 如启动,目前越%50的命中率, 可以通过对启动经常调用的方法符号重排,减少跨页访问,节省启动时间,
- 请求调页策略
- 从何处调入页面
- 系统拥有足够的对换区空间
- 系统缺少足够的对换空间
- UNIX方式: 与进程相关文件都放在文件区,未运行的页面都需要从文件区调入
抖动
- 刚刚换出的页面马上又被换入
- 主要原因: 某个进程频繁访问的页面数目高于可用的物理页帧数目
工作集
- 在某段时间内,进程访问的页面集合,基于局部性原理,可以用最近访问的页面来确定工作集,动态分配和回收内存块,避免抖动
地址翻译
- TODO: