本篇笔记课程来源:王道计算机考研 操作系统
【操作系统】第三章:内存管理
一、内存管理的基本概念
1. 基本概念
- 内存:可存放数据。程序执行前,需要先放到内存中才能被 CPU 处理 —— 缓和 CPU 与硬盘之间的速度矛盾。
- 编译:由编译程序将用户源代码编译成若干个目标模块(把高级语言翻译为机器语言)
- 链接:由链接程序将编译后形成的一组目标模块,以及所需库函数链接在一起,形成一个完整的装入模块和逻辑地址
- 装入模块:可理解为 可执行文件(*.exe)
- 装入(装载):由装入程序将装入模块装入内存运行,装入后形成物理地址。
2. 存储单元
- 内存中划分成了一个一个的存储单元,每个存储单元对应一个内存地址。
- 存储单元的大小:
- 如果计算机 “按字节编码”,则每个存储单元大小为 1 字节(1B)
- 如果计算机 “按字编码”,字长 16 位,则每个存储单元大小为 1 个字,每个字的大小为 16 个二进制位
3. 内存地址
- 地址分类:
- 逻辑地址:也叫相对地址,程序经过编译、链接后生成的指令中指明的是逻辑地址。
- 物理地址:也叫绝对地址,数据在内存中实际存放的地址。
4. 装入方式(地址转换)
将指令中的逻辑地址转换为物理地址,三种装入方式:
- 绝对装入
- 概念:在编译时,如果知道程序将放在内存中的哪个位置,编译程序将产生绝对地址的目标代码。装入程序按照装入模块中的地址,将程序和数据装入内存。
- 特点:灵活性低,只适用于单道程序环境。
- 静态重定位
- 概念:又称可重定位装入。根据内存的当前情况,将装入模块装入到内存的适当位置。装入时对内存进行 “重定位”,将逻辑地址变换为物理地址(地址变换是在装入时一次完成的)。
- 特点:用于早期的多道批处理操作系统。一个作业在装入内存时,必须分配其要求的全部空间,如果没有足够的内存,就不能转入该作业。作业一旦进入内存后,在运行期间就不能再移动,也不能再申请内存空间。
- 动态重定位
- 概念:又称动态运行时装入。把地址转换推迟到程序真正要执行时才进行。因此装入内存后所有的地址依然是逻辑地址。这种方式需要一个重定位寄存器(存放装入模块的起始地址)的支持。
- 特点:用于现代操作系统。允许程序在内存中发生移动。并且可将程序分配到不连续的存储区中;在程序运行前只需装入它的部分代码即可投入运行,然后在程序运行期间,根据需要动态分配内存;便于程序段的共享,可以向用户提供一个比存储空间大得多的地址空间。
5. 链接方式
- 静态链接:在程序运行之前,先将各目标模块以及它们所需的库函数链接成一个完整的可执行文件(装入模块),之后不再拆开。
- 装入时动态链接:将各目标模块装入内存时,边装入边链接的链接方式。
- 运行时动态链接:在程序执行中需要该目标模块时,才对它进行链接。优点是便于修改和更新,便于实现对目标模块的共享。
二、内存管理的作用
1. 分配与回收
- 操作系统负责 内存空间的分配与回收
2. 内存扩展
- 操作系统需要提供某种技术(虚拟技术)从逻辑上 对内存空间进行扩充
- 虚拟技术也是操作系统的虚拟性
3. 地址转换
- 操作系统需要提供 地址转换功能 ,负责程序的逻辑地址与物理地址的转换
- 为了使编程更方便,程序员写程序时只需要关注指令、数据的逻辑地址。而逻辑地址到物理地址的转换(地址重定向)应该由操作系统负责。
- 三种装入方式:绝对装入、可重定位装入、动态运行时装入
4. 内存保护
- 操作系统需要提供 内存保护 功能。保证各进程在各自存储空间内运行,互不干扰。
- 内存保护可采取的方式:
- 在 CPU 中设置一对上、下限寄存器,存放进程的上、下限地址。进程的指令要访问某个地址时,CPU 检查是否越界。
- 采用重定位寄存器(基址寄存器)和界地址寄存器(限长寄存器)进行越界检查。重定位寄存器中存放进程的起始物理地址,界地址寄存器存放进程的最大逻辑地址。
三、覆盖与交换
- 内存空间的扩充包括了覆盖技术、交换技术、虚拟存储技术。这节主要记录覆盖技术和交换技术。
1. 覆盖技术
- 引入原因:早起的计算机内存很小,因此经常会出现内存大小不够的情况。于是引入了覆盖技术,用来解决“程序大小超过物理内存总和“的问题。
- 思想:
- 将程序分为多个段(多个模块),内存中分为一个”固定区“和若干个”覆盖区“。
- 需要常驻内存的段放在”固定区“中,调入后就不再调出(除非运行结束),不常用的段放在“覆盖区”,需要用时调入内存,用不到时调出内存。
- 缺点:对用户不透明,增加了用户编程负担。必须由程序员声明覆盖结构,操作系统完成自动覆盖。只用于早期的操作系统中。
2. 交换技术
- 思想:内存空间紧张时,系统将内存中某些进程暂时换出外存,把外存中某些已具备运行条件的进程换入内存(进程在内存与磁盘间动态调度)
- 中级调度(内存调度),就是要决定将哪个处于挂起状态的进程重新调入内存。
- 暂时换出外存等待的进程状态为挂起状态(挂起态,suspend)
- 挂起态又可以进一步细分为就绪挂起、阻塞挂起两种状态
- 实现:
- 通常把磁盘空间氛围文件区和对换区两部分。
- 文件区主要用于存放文件,主要追求存储空间的利用率,因此对文件区空间的管理采用离散分配方式
- 对换区空间只占磁盘空间的小部分,被换出的进程数据就存放在对换区。由于对换的速度直接影响到系统的整体速度,因此对换区空间的管理主要追求换入换出速度,因此通常对换区采用连续分配方式。
- 总之,对换区的IO速度比文件区的更快。
- 交换通常在许多进程运行且内存吃紧时进行,而系统负荷降低就暂停。(如果发现许多进程运行时经常发生缺页,就说明内存紧张,此时可以换出一些进程)
- 可优先换出阻塞进程、优先级低的进程;为了防止优先级低的进程在被调入内存后很快又被换出,还会考虑进程在内存的驻留时间
- PCB会常驻内存,不会被换出内存
- 通常把磁盘空间氛围文件区和对换区两部分。
3. 两种技术的区别
- 覆盖技术是在同一个程序或进程中的
- 交换技术是在不同进程(或作业)之间的
四、连续分配管理方式
- 连续分配:指为用户进程分配的必须是一个连续的内存空间
- 内部碎片:分配给某个进程的内存区域中,如果有些部分没有用上。
- 外部碎片:内存中的某些空闲分区由于太小而难以利用。
1. 单一连续分配
- 内存被分为系统区和用户区。
- 系统区通常位于系统的低地址部分,用于存放操作系统相关数据
- 用户区存放用户进程相关数据
- 内存中只能有一道用户进程,用户进程独占整个用户区空间
- 优点:实现简单,无外部碎片;可以采用覆盖技术扩充内存;不一定需要采取内存保护
- 缺点:只能用于单用户、单任务的操作系统中,有内部碎片;存储器利用率低。
2. 固定分区分配
- 将整个用户空间划分为若干个固定大小的分区,在每个分区中只装入一道作业。
- 固定分区分配分为:分区大小相等、分区大小不等
- 分区大小相等:缺乏灵活性,但是很适合用于一台计算机控制多个相同对象的场合
- 分区大小不等:增加了灵活性,可以满足不同大小的进程需求。根据常在系统中运行的作业大小情况进行划分
- 分区说明表:
- 操作系统需要建立分区说明表,来实现各个分区的分配与回收。
- 每个表项对应一个分区,通常按分区大小排列。
- 每个表项包括对应分区的大小、起始地址、状态(是否已分配)
- 优点:实现简单,无外部碎片
- 缺点:当用户程序太大时,可能所有的分区都不能满足需求,此时不得不采用覆盖技术来解决,但又会降低性能;会产生内部碎片,内存利用率低。
3. 动态分区分配
- 动态分区分配又称为可变分区分配,这种分配方式不会预先划分内存分区,而是在进程装入内存时,根据进程的大小动态地建立分区,并使分区的大小正好适合进程的需要。因此系统分区的大小和数目是可变的。
- 记录内存的使用情况有两种常用的数据结构:
- 空闲分区表:每个空闲分区对应一个表项。表项中包括分区号、分区大小、分区起始地址等信息。
- 空闲分区链:每个分区的起始部分和末尾部分分别设置前向指针和后向指针。起始部分处还可记录分区大小等信息。
- 把一个作业装入内存时,须按照一定的动态分区分配算法,从空闲分区表(或空闲分区链)中选出一个分区分配给该作业。
- 相邻的空闲区间需要合并,分区分配和回收的四种情况:
- 回收区之后有相邻的空闲分区
- 回收区之前有相邻的空闲分区
- 回收区前、后都有相邻的空闲分区
- 回收区前、后都没有相邻的空闲分区
- 动态分区分配没有内部碎片,但是有外部碎片。可以通过紧凑(拼凑,Compaction)技术来解决外部碎片。
五、动态分区分配算法
1. 首次适应算法(First Fit)
- 算法思想:每次都从低地址开始查找,找到第一个能满足大小的空闲分区。
- 算法实现:空闲分区以地址递增的次序排序。每次分配内存时顺序查找空闲分区链(或空闲分区表),找到大小能满足要求的第一个空闲分区。
2. 最佳适应算法(Best Fit)
- 算法思想:尽可能多地留下大片的空闲区,优先使用更小的空闲区。
- 算法实现:空闲分区按容量递增次序链接。每次分配内存时顺序查找空闲分区链(或空闲分区表),找到大小能满足要求的第一个空闲分区。
- 缺点:每次都选最小的分区进行分配,会留下越来越多的、很小的、难以利用的内存块。因此这种算法会产生很多的外部碎片。
3. 最坏适应算法(Worst Fit)
- 有称最大适应算法(Largest Fit)
- 算法思想:每次分配时优先使用最大的连续空闲区,这样分配后剩余的空闲区就不会太小,更方便使用。
- 算法实现:空闲分区按容量递减次序链接。每次分配内存时顺序查找空闲分区链(或空闲分区表),找到大小能满足要求的第一个空闲分区。
- 缺点:每次都选最大的分区进行分配,虽然可以让分配后留下的空闲区更大,更可用,但是这种方式会导致较大的连续空闲区被迅速用完。如果之后有“大进程”到达,就没有内存分区可用。
4. 邻近适应算法(Next Fit)
- 算法思想:对首次适应算法的改进,每次都从上次查找结束的位置开始检索,以减少查找开销。
- 算法实现:空闲分区以地址递增的顺序排列(可排成一个循环链表)。每次分配内存时从上次查找结束的位置开始查找空闲分区链(或空闲分区表),找到大小能满足要求的第一个空闲分区。
5. 四种算法比较
| 算法 | 算法思想 | 分区排列顺序 | 优点 | 缺点 |
|---|---|---|---|---|
| 首次适应算法 | 从头到尾找适合的分区 | 以地址递增次序排序 | 综合看性能最好。算法开销小,回收分区后一般不需要对空闲分区队列重新排序 | |
| 最佳适应算法 | 优先使用更小的分区,以保留更多大分区 | 以容量递增次序排列 | 会有更多的大分区被保留下来,更能满足大进程需求 | 会产生很多太小的、难以利用的碎片;算法开销大,回收分区后可能需要对空闲分区队列重新排序 |
| 最坏适应算法 | 优先使用更大的分区,以防止产生太小的不可用的碎片 | 以容量递减次序排列 | 可以减少难以利用的小碎片 | 大分区容易被用完,不利于大进程;算法开销大 |
| 邻近适应算法 | 以首次适应演变而来,每次从上次查找结束位置开始查找 | 以地址递增次序排列(可排成循环链表) |

最低0.47元/天 解锁文章
1339

被折叠的 条评论
为什么被折叠?



