前置:简单的个人学习笔记上传,仅供参考,想要md文档的可以评论留言
参考内容
CSDN博主 BitHachi的博文 《王道操作系统》学习笔记总目录+思维导图
CSDN博主 小林coding的图解操作系统
3 内存管理
3.1 内存及进程运行的基本原理
-
内存
- 存储单元,内存从0开始,每个地址对应一个存储单元。
- 按字节编址则每个存储单元的大小为1字节,8个bit。
- 按字编址,则每个存储单元的大小为一个字。
-
从代码到运行
- 编译
- 由编译程序将用户源代码编译为若干个目标模块(把高级语言翻译为机器语言)
- 链接:将编译后形成的一组目标模块,以及所需的库函数链接在一起,形成一个完整的装入模块
- 静态链接
- 在程序运行之前,先将各目标模块以及它们所需的库函数连接成一个完整的可执行文件,之后不可拆分。
- 装入时动态连接
- 将各目标模块装入内存时,边装入边链接
- 运行时动态链接
- 在程序执行中需要该目标模块时才对它进行链接。
- 静态链接
- 装入
- 绝对装入:编译时就产生绝对地址
- 只适用于单道程序环境
- 静态重定位:装入时对逻辑地址进行重定位,将逻辑地址变换为物理地址
- 将一个作业装入内存时,必须分配其要求的全部内存空间,装入后在运行期间不能移动,也不能申请新的内存
- 动态重定位:程序真正运行时才会将逻辑地址转化为真实的物理地址,需要重定位寄存器的支持
- 允许程序在内存中发生移动,可以将程序分配到不连续的存储区中。
- 绝对装入:编译时就产生绝对地址
- 编译
3.2 内存空间的分配,回收以及扩充
3.2.1 内存空间的分配
- 非连续分配
- 页分配
- 段分配
- 段页式分配
- 连续分配
- 单一连续分配
- 仅支持单道程序,内存分为系统区和用户区,用户程序放在用户区
- 固定分区分配
- 支持多道程序,内存空间分为若干个固定大小的分区,每个分区装入一道作业
- 无外部碎片,有内部碎片
- 动态分区分配
- 进程转入内存时根据进程的大小动态地建立分区
- 无内部碎片,有外部碎片
- 单一连续分配
3.2.2 动态分区的分配算法
-
首次适应算法
- 空闲分区以地址递增的次序排列
- 每次从低地址开始查找,根据空闲分区表或者空闲分区链找到第一个能够满足大小的空闲区间。
- 然后更新空闲分区表或者空闲分区链
-
最佳适应算法
- 空闲分区按照容量递增次序链接
- 分配内存时按顺序查找空闲分区链,找到大小能够满足要求的第一个空闲分区
- 然后更新空闲分区表或者空闲分区链
- 缺点
- 每次选小的进行分配,会产生很多很小的难以利用的内存块
-
最坏适应算法
- 空闲分区按照容量递减次序链接
- 每次分配时按照顺序,找到满足要求的第一个分区
- 然后更新空闲分区表或者空闲分区链
- 缺点
- 导致大的空闲分区被迅速用完,难以给后续的大进程分配空间
-
邻近适应算法
- 空闲分区以地址递增的顺序排列(可排列成一个循环链表)
- 每次分配内存时从上次查找结束的位置开始查找空闲分区链
-
内存空间的回收
- 空闲空间要合并
-
内存的扩充
- 覆盖技术
- 一个固定区
- 存放最活跃的程序段
- 固定区中的程序段在运行过程中不会调入调出
- 若干个覆盖区
- 不可能被同时访问的程序段可以共享一个覆盖区
- 覆盖区中的程序段在运行过程中会根据需要调入调出
- 缺点
- 必须由程序员声明覆盖结构,由操作系统完成自动覆盖
- 对用户不透明,增加编程负担
- 一个固定区
- 交换技术
- 在磁盘中声明一份交换区
- 当内存紧张时,换出某些进程腾出内存空间,再换入某些进程
- 覆盖技术
3.3 页存储
-
真实的内存空间被分为大小相等的分区,每个分区就是一个“页框”(“页帧”,“内存块”,“物理块”),每个分区都有一个编号,编号从0开始。
Linux中标准页的大小为 4KB
通过 getconf PAGESIZE 命令可以查看页的大小
-
进程的地址空间也分为与页框大小相等的页,每个页面也有编号,也是从0开始
-
进程的页与内存中的页通过页表实现一一对应
-
逻辑地址的页号,页内偏移量
- 页号 = 逻辑地址/页面长度 (除法取整)
- 业内偏移量 = 逻辑地址%页面长度 (取余)
- 如果每个页面的大小为2^kB,用二进制表示逻辑地址,则末尾的K位对应的十进制数就是页内偏移量,前面的二进制数对应的十进制数就是页号
-
页表
- 每个进程有一个页表
- 进程的每一页对应一个页表项
- 每个页表项由页号和块号组成
- 页表项记录进程页面和实际存放的内存块之间的对应关系
- 每个页表项的长度是相等的,页号是隐藏的
- 页表项连续存放再内存中
- 页表项的长度可以确定
- 知道页表再内存中存放的起始地址
-
快表(Translation Lookaside Buffer,TLB)
- 根据局部性原理,引入一种访问速度比内存快很多的高速缓存,将常访问的页表项放到TLB中,每次访问时先查询TLB未命中再查询内存中的页表。
-
多级页表
- 页表必须连续存放,且根据局部性原理,进程一段时间内只需访问某几个页面就可以正常运行,没有必要让整个页表都常驻内存。
- 可以引入多级页表,对页表再次进行分组
3.3 段存储与段页式存储
3.3.1 段存储
- 按照程序本身的逻辑,可以将程序划分为若干个段,每个段有不同的属性逻辑
- 分段机制下的进程地址
- 段选择子
- 段内偏移量
- 段表
- 每个段对应段表中的一个段表项
- 每个段表项记录了段的基地址以及段的长度(段界限) 段内偏移量不能超过段界限
- 寻址过程
- 根据进程地址得到段号,判断段号是否越界
- 查询段表,得到段表项位置检查段内偏移量是否超过段界限
- 段基址+段内偏移量得到物理地址
3.3.2 段页式存储
-
段页式存储
- 先根据程序逻辑进行分段
- 在对每一段进行分页
-
段页式地址结构
- 段号
- 段表内容
- 页表长度
- 页表存放的块号
- 段表内容
- 页号
- 页对应的块号
- 页内偏移量
- 段号
3.4 虚拟内存管理
3.4.1 虚拟内存
- 基于局部性原理,在程序装入时,可以将程序中很快用到的部分装入内存,暂时用不到的部分留到外存,当访问的信息不在内存时,由操作系统负责将所需的信息从外存调入内存
- 主要特征
- 多次性:无需在作业运行时一次性全部装入内存,而是允许被分成多次调入内存。
- 交换性:在作业运行时无需一直常驻内存,而是允许在作业运行过程中,将作业换入、换出。
- 虚拟性:从逻辑上扩充了内存的容量,使用户看到的内存容量,远大于实际的容量。
3.4.2 请求分页管理
-
主要功能
- 请求调页
- 缺页中断
- 操作系统的缺页中断处理程序处理中断
- 缺页的进程阻塞,被放入阻塞队列,当调页完成后再将其唤醒放回就绪队列
- 缺页中断
- 页面置换
- 请求调页
-
请求页表
- 页号
- 内存块号
- 状态位
- 是否已经调入内存
- 访问字段
- 可以记录最近被访问过的次数,或者记录上次访问的时间,供页面置换算法参考
- 修改位
- 页面调入内存后是否被修改过
- 外存地址
- 页面在外存中存放的位置
-
请求访问流程
3.4.3 页面置换算法
- 最佳置换算法(OPT)
- 每次选择淘汰的页面是以后永不使用或者在最长时间内不再被访问的页面
- 先进先出置换算法(FIFO)
- 每次淘汰的页面是最早进入内存的页面
- 该算法会产生Belady异常
- 当为进程分配的物理块数增大时,缺页次数不减反增的异常现象
- 最近最久未使用置换算法(least recently used,LRU)
- 根据请求页表的页表项中的访问字段淘汰最近最久未使用的页面
- 可以逆向检查此时在内存中的页面号,逆向扫描过程中最后一个出现的页号就是要淘汰的页面
- 该算法需要专门的硬件支持,实现困难,开销大
- 时钟置换算法——CLOCK或者最近未用算法(NRU)
- 将内存中的页面通过链接指针链接成一个循环队列,通过循环访问页的访问位,如果是0就将该页换出,如果是1则将它置0
- 改进型的时钟置换算法
- 通过访问位和修改位一起考虑置换页面,(访问位,修改位)
- 第一轮:------->没访问且没修改
- 先找(0,0)的页进行替换,没有则进行下一轮
- 第二轮:-------->没访问但修改过
- 找第一个(0,1)的页进行替换,并将所有扫描过的页的访问位设为0,没有找到则进行下一轮
- 第三轮:--------->访问过但没修改
- 重新扫描,查找第一个(0,0)的页替换,没有则进行下一轮扫描
- 第四轮:--------->访问过且修改过
- 重新扫描,查找第一个(0,1)的帧用于替换
- 第一轮:------->没访问且没修改
- 通过访问位和修改位一起考虑置换页面,(访问位,修改位)
3.4.4 页面分配策略
-
驻留集
- 请求分页存储管理中给进程分配的物理块的集合
- 采用虚拟存储技术的系统,驻留集大小一般小于进程的总大小
-
页面分配策略
- 固定分配
- 分配一组固定数目的物理块,在进程运行期间不再改变
- 可变分配
- 分配的物理块数目在运行期间可变
- 固定分配
-
置换策略
-
局部置换
- 缺页时只能选进程自己的物理块进行置换
-
全局置换
- 可已将操作系统保留的空闲物理块分配给缺页进程,也可以将别的进程持有的物理块置换到外存,再分配给缺页进程
全局置换会改变进程的物理块的个数,因此只适用于可变分配
-
-
分配置换规则
- 固定分配局部置换:系统为每个进程分配一定数量的物理块,在整个运行期间都不改变。若进程在运行中发生缺页,则只能从该进程在内存中的页面中选出一页换出,然后再调入需要的页面。这种策略的缺点是:很难在刚开始就确定应为每个进程分配多少个物理块才算合理。(采用这种策略的系统可以根据进程大小、优先级、或是根据程序员给出的参数来确定为一个进程分配的内存块数)
- 可变分配全局置换:刚开始会为每个进程分配一定数量的物理块。操作系统会保持一个空闲物理块队列。当某进程发生缺页时,从空闲物理块中取出一块分配给该进程;若已无空闲物理块,则可选择一个未锁定的页面换出外存,再将该物理块分配给缺页的进程。采用这种策略时,只要某进程发生缺页,都将获得新的物理块,仅当空闲物理块用完时,系统才选择一个未锁定的页面调出。被选择调出的页可能是系统中任何一个进程中的页,因此这个被选中的进程拥有的物理块会减少,缺页率会增加。
- 可变分配局部置换:刚开始会为每个进程分配一定数量的物理块。当某进程发生缺页时,只允许从该进程自己的物理块中选出一个进行换出外存。如果进程在运行中频繁地缺页,系统会为该进程多分配几个物理块,直至该进程缺页率趋势适当程度;反之,如果进程在运行中缺页率特别低,则可适当减少分配给该进程的物理块。
-
调页策略
- 预调页策略
- 进程首次调入时
- 请求调页策略
- 缺页请求调入时
- 磁盘I/O开销较大
- 预调页策略
-
调页的位置
- 系统拥有足够的交换区空间:页面的调入、调出都是在内存与交换区之间进行,这样可以保证页面的调入、调出速度很快。在进程运行前需将进程相关的数据从文件区复制到交换区。
- 系统缺少足够的交换区空间:凡是不会被修改的数据都直接从文件区调入,由于这些页面不会被修改,因此换出时不必写回磁盘,下次需要时再从文件区调入即可。对于可能被修改的部分,换出时需写回磁盘交换区,下次需要时再从交换区调入。
- UNIX方式:运行之前进程有关的数据全部放在文件区,故未使用过的页面,都可从文件区调入。若被使用过的页面需要换出,则写回交换区,下次需要时从交换区调入。
-
抖动现象
- 刚换出的页面又要换入内存,刚换入的页面又要换出外存,频繁的页面调度行为称为抖动
- 主要原因
- 进程频繁访问的页面数目高于可用的物理块
-
工作区
- 某段时间间隔内,进程实际访问的页面的集合
- 驻留集大小不能小于工作集的大小