操作系统—第三章 内存管理
3.1内存管理概念
操作系统对内存的划分和动态分配
主要功能:
- 内存空间的分配与回收
- 地址变换:将逻辑地址转换成相应的物理地址
- 内存空间的扩充:利用虚拟存储技术从逻辑上扩充内存
- 内存共享:允许多个进程访问内存的同一部分
- 存储保护:保证各个进程在各自的存储空间内运行,互不干扰
逻辑地址与物理地址
1.相对地址(逻辑地址)
指每个模块都从0号开始编址,不同进程可以拥有相同的逻辑地址,这些相同的逻辑地址可以映射到主存的不同位置
链接程序:将各个模块链接成一个完整的可执行目标程序,顺序依次给各个模块相对地址构成统一的从0号单元开始编址的逻辑地址空间(虚拟地址空间)
2.物理地址空间:
内存中物理单元的集合,是地址转换的最终地址
当装入程序将可执行代码装入内存时,必须通过地址转换将逻辑地址转换成物理地址,这个过程称为地址重定位
3.内存管理部件MMU
将进程使用的逻辑地址转换为物理地址
程序的链接与装入
将用户源程序变为可在内存中执行的程序,通常需要以下几个步骤:
- 编译:由编译程序将用户源代码编译成若干目标模块
- 链接:由链接程序将编译后形成的一组目标模块,以及它们所需的库函数链接在一起,形成一个完整的装入模块
- 装入:由装入程序将装入模块装入内存运行
程序的装入
将一个装入模块装入内存时,有以下三种装入方式
1.绝对装入
- 只适用于单道程序环境
- 知道程序将放到内存的哪个位置,编译程序产生绝对地址的目标代码
- 程序中的逻辑地址与实际内存地址完全相同
2.可重定位装入(静态重定位)
- 装入时对目标程序中的相对地址的修改过程称为重定位
- 只能对程序中的地址进行一次修改,而不能动态调整
- 必须分配连续内存空间
3.动态运行时装入(动态重定位)
-
将地址转换推迟到程序真正要执行时才进行,装入内存后的所有地址均为相对地址
-
这种方式需要:
- 重定位寄存器(也称基址寄存器),存放进程的基地址,整个系统中只设置一个
- 可重定位装入程序,在重定位的过程中执行
- 地址变换机构,将指令中的逻辑地址与重定位寄存器中的基地址相加得到物理地址
-
优点:
- 可以将程序分配到不连续的存储器;
- 根据需要动态申请分配内存;
- 便于程序段的共享
- 能保证一个程序在主存中被改变存放位置后仍能正常执行
程序的链接
1.静态链接
在程序运行之前,先将个目标模块及它们所需的库函数链接成一个完整的装入模块,以后不再拆开
2.装入时动态链接
再装入模块时,采用边装入边链接的方式
优点:便于修改和更新,便于实现对目标模块的共享(“目标模块的共享”指的是在多个程序或模块之间复用同一个目标文件(编译产物),或者在运行时多个程序共享同一段目标模块的代码和数据,以提高效率、节省资源。)
3.运行时动态链接
在程序执行中需要某目标模块时,才对它进行链接
优点:能加快程序的装入过程,还可节省空间
进程的内存映射
当一个程序调入内存运行时,就构成了进程的内存映射,一个进程的内存映射一般有几个要素:
- 代码段
- 数据段
- 进程控制块PCB
- 堆
- 栈
内存保护
确保每个进程都有一个单独的内存空间,需要由操作系统和硬件机构合作完成
上下限地址保护
在CPU中设置一对上下限寄存器,存放用户进程在主存中的下限和上限地址
界地址保护
采用重定位寄存器(也称基地址寄存器)和界地址寄存器(也称限长寄存器)进行越界检查
- 重定位寄存器存放进程的起始物理地址
- 界地址寄存器存放进程最大逻辑地址
内存管理部件MMU将逻辑地址与界地址寄存器进行比较,未越界则加上重定位寄存器的值后映射成物理地址
内存共享
只有只读的区域才可以共享
可重入代码(纯代码)
允许多个进程同时访问但不允许被任何进程修改的代码
**最大的优点:**减少了对程序段的调入/调出,减少了对换数量
数据区
将在执行中可能改变的部分复制到数据区,程序在执行时只需对该私有数据区中的内存进行修改,并不去改变共享的代码
连续分配方式
指为一个用户程序分配一个连续的内存空间,主要包括:
1.单一连续分配
内存被分为系统区和用户区
- 系统区仅供操作系统使用,通常在低地址部分
- 用户区内存中仅有一道程序,即用户程序独占整个用户区
**优点:**简单、五外部碎片;不需要进行内存保护
**缺点:**只能用于单用户、单任务的操作系统中;有内部碎片;内存的利用率极低
2.固定分区分配
最简单的一种多道程序存储管理方式,将用户内存空间提前划分为若干固定大小的分区,每个分区只装入一道作业
- 分区大小相等
- 分区大小不等
**优点:**无外部碎片
缺点:内存的利用率低,并存在两个问题①程序太大而放不进任何一个分区②程序小于固定分区大小也要占用一个完整的内存分区,存在空间浪费,这种现象称为内部碎片
3.动态分区分配(可变分区分配)
基本原理
根据进程的实际需要,动态地为之分配内存,
随着时间的推移,内存中会产生越来越多的小内存块,内存的利用率也随之下降,这些小内存块被称为外部碎片
虽然动态分区分配分配的是连续的物理空间,但每个进程仍使用从 0 开始的逻辑地址空间,所以仍需要硬件地址变换机构(基址 + 限长寄存器)来把逻辑地址转为物理地址,并实现内存保护。
内存回收
设这一张空闲分区链表,可以按始址排序
若有相邻的空闲分区,则合并两个分区,并修改为一个分区表项
若没有相邻的空闲分区,为回收区新建一个表项,插入空闲分区链
基于顺序搜索的分配算法
依次搜索空闲分区链上的空闲分区,以寻找一个大小满足要求的分区
- 首次适应算法:空闲分区按地址递增的次序排列,每次顺序找到第一个能满足大小
- 邻近适应算法(循环适应算法):按地址递增排序,分配内存时从上次查找结束的位置开始继续查找
- 最佳适应算法:空闲分区按容量递增的次序排序,每次顺序找到能满足大小的最小空闲分区分配给作业
- 最坏适应算法:空闲分区按容量递减的次序排序,每次从最大的空闲分区中分割一部分空间给作业
首次适应算法开销小,性能最好,回收分区也不需要对空闲分区重新排序
基于索引搜索的分配算法
思想:对于每类大小相同的空闲分区,单独设立一个空闲分区链,并设置一张索引表来管理这些空闲分区链。当为进程分配空间时,在索引表中查找所需空间大小对应的表项。在大、中型系统中往往采用索引分配算法
- 快速适应算法:首先从索引表中找到能容纳它的最小空闲分区链表,然后从链表中取下第一块进行分配
- **优点:**查找效率高、不会产生内存碎片
- **缺点:**回收内存时,需要有效地合并分区,算法复杂,系统开销大
- 伙伴系统:所有分区的大小均为2的k次幂,当需要大小为n的分区时(2i−1<n≤2i2^{i-1}<n≤2^i2i−1<n≤2i),从大小为2i2^i2i开始往更大的的空闲分区链找,若找到的空闲分区链不是2i2^i2i,则将其等分开为两个分区,分区称为一对伙伴,其中一个用于分配,而将另一个加入大小为2i2^i2i的空闲分区链,回收时需要需要将相邻的空闲伙伴分区合并成更大的分区
- 哈希算法:构造一张以空闲分区大小为关键字的哈希表
基本分页存储管理(固定分区大小的非连续分配方式)
思想:将内存空间分为若干固定大小(如4KB)的分区,称为页框(也称为页帧或物理块)
如果知道主存大小和页框数量,则页框大小=主存大小/页框数量
进程的逻辑地址空间也分为与块大小相等的若干区域,称为页(也称为页面)
操作系统以页框为单位分配内存空间
**优点:**不产生外部碎片;进程只会在最后一个不完整的块申请一个主存块空间时,才产生主存碎片(主要是页内碎片)
块的大小相对分区要小很多,产生的内存碎片(也称页内碎片)相对进程很小
基本概念
页面和页面大小:
-
进程的逻辑地址空间中的每个页面有一个编号,称为页号,从0开始
-
内存空间中的每个页框也有一个编号,称为页框号(或物理块号),从0开始
-
要为每个页面分配内存中的可用页框
地址结构:
- 包含两部分:前一部分为页号,后一部分为页内偏移量
页号的位数表示了最多允许有多少页,也指一页可以存放多少个页表项
页内偏移量位数表示了每页大小
整个位数表示了主存的最大容量
页表(页面映射表):
- 每个进程有一个页表,用于将它的逻辑地址空间映射到物理地址空间。
- 进程的每个页面对应一个页表项,每个页表项由页号和块号组成,记录了页面在内存中对应的物理块号
- 页表的作用是实现从页号到物理块号的地址映射
- 驻留在内存中
基本地址变换机构
地址变换机构的任务是将逻辑地址转换为内存中的物理地址
系统之设置一个页表寄存器(PTR),存放页表在内存的始址F和页表长度M
查找页表的工作是由硬件自动完成的
变换过程:
- 计算页号P=逻辑地址A/页面大小L,页内偏移量W=A%L
- 若页号P≥页表长度M,则越界中断
- 页号P对应的页表项地址=页表始址F+页号P*页表项长度,查出物理块号(或页框号)b
- 计算物理地址E=bL+W
具有快表的地址变换机构
**快表(TLB,也称相联存储器):**用来存放当前访问的若干页表项,以加快地址变换过程
主存中的页表称为慢表
变换过程:
- 将页号与快表中的所有页号进行比较,若找到读取物理块号,存取数据仅一次访存
- 若未找到,则要访问内存中的页表,并找到页表项后存入快表,存取数据需要两次访存
一般快表的命中率可达90%以上,快表的有效性基于著名的局部性原理
两级页表
进程在执行时不需要将所有页调入内存页框,也不应该将所有页表项都调入内存
解决页表内存大且需要连续的问题:①采用离散分配方式②只将部分页表项调入内存
**外层页表(也称页目录):**为离散分配的页表再建立一张页表
需要在系统中增设一个外层页表寄存器(也称页目录基址寄存器),用于存放页目录始址
基本分段存储管理(不固定分区大小的非连续分配方式)
思想:每个段的长度不固定,根据实际需求动态分配,需要多少内存操作系统就分配多少内存
**优点:**不会产生内部碎片
**主要目的:**满足用户方便编程、分段共享、分段保护、动态链接、动态增长
基本概念
分段:
- 在用户编程时决定
- 分段把程序按逻辑模块划分,有利于程序的动态链接
- 动态链接是指:程序运行时,才将某些模块或库装入内存并连接,而不是在编译时就全部链接好。
- 分段存储管理的逻辑地址由段号S与段内偏移量W两部分组成
段表:
- 每个进程都有一张逻辑地址与内存空间映射的段表
- 每个段表项对应进程中的一段
- 段表项记录了该段在内存中的始址和段的长度
- 系统提供用户的物理地址空间大小=总空间大小-段表长度
地址变换机构
系统中设置一个段表寄存器,用于存放段表始址F和段表长度M
变换过程:
- 从逻辑地址A中取出段号S和段内偏移量W
- 若段号S≥段表长度M,则越界中断
- 段号P对应的段表项地址=段表始址F+段号P*段表项长度,取出段长C
- 若段内偏移量W≥段长C,则越界中断
- 取出该段表项的该段始址b
- 计算物理地址E=b+W
段的共享与保护
共享段表,所有共享的段都占一个表项,用来实现多个进程共享一段代码或数据
共享计数器count记录有多少进程正在共享该段,为0才回收该段所占的内存区
每个进程用自己进程的段号去访问该共享段
分页和分段的区别
- 页是信息的物理单位,分页的主要目的是提高内存利用率,是系统行为用户不可见
- 段时信息的逻辑单位,分段的主要目的时更好地满足用户需求,用户可见
- 页的大小固定且系统决定,段的大小不固定用户决定
- 分页管理的地址空间是一维的,分段管理的地址空间是二维的
段页式存储管理
分页能提高内存效率,分段能有利于共享和保护
段页式中进程的地址空间分为若干逻辑段,然后将各段分成若干大小固定的页
对内存的分配以物理块为单位
**实现原理:**用分段方法来分配和管理用户地址空间,用分页方法来管理物理存储空间
地址变换
- 通过段表查到页表始址
- 通过页表找到物理块号
- 形成物理地址
3.2虚拟内存管理
基本概念
传统存储器管理方式共同的特征:
- 一次性:全部装入内存后才能开始运行
- 驻留性
局部性原理
**高速缓存技术:**快表、页高速缓存、虚拟内存技术
- 时间局部性:某条指令一旦执行,不久后可能再次执行
- 空间局部性:某个存储单元被访问,不久后附近存储单元也将被访问
虚拟存储器的定义和特征
特点:
- 部分装入:仅将程序当前运行要用到的少数页面或段装入内存,而将其余部分留在外存
- 请求调页/段:当所访问的信息不在内存时,操作系统负责将所需信息从外存调入内存
- 页面置换(段置换):当内存空间不够时,操作系统负责将内存中暂时用不到的信息换出到外存
特征:
- 多次性:只将当前要运行的那部分程序和数据装入内存(虚拟存储器最重要的特征)
- 对换性:将暂不使用的程序和数据调出内存
- 虚拟性:逻辑上扩充内存容量
虚拟内存技术的实现
- 请求分页存储管理
- 请求分段存储管理
- 请求段页式存储管理
**硬件支持:**内存、外存、页/段表机制、中断机构、地址变换机构
请求分页管理方式
为了实现请求分页,还需要页表机制、缺页中断机制、地址变换机构
1.页表机制
- 状态位P:标记该页是否已调入内存
- 访问字段A:记录本页一段时间的访问量/多久时间未被访问
- 修改位M:标记该页是否被修改过
- 外存地址:记录该页都的外存地址
2.缺页中断机制
每当要访问的页面不在内存时,便产生一个缺页中断
3.地址变换机构
增加了产生和处理缺页中断,及从内存中换出一页的功能
页框分配
对于分页式的虚拟内存,操作系统需要决定都多少页,即决定给特定的进程分配几个页框
**驻留集:**给一个进程分配的页框的集合
内存分配策略
- 固定分配:系统一开始就给每个进程固定数量的页框,在运行过程中不再改变。
- 可变分配:系统在运行时可以根据实际情况(如缺页频率、进程状态)动态调整某个进程所拥有的页框数量。
- 局部置换:当进程发生缺页时,只允许从该进程自身的页框中选择一页淘汰。
- 全局置换:当进程发生缺页时,可以从所有进程的页框中任选一页进行淘汰,不局限于本进程。
固定分配 + 局部置换
- 最常见的组合
- 每个进程分配固定页框,只能替换自己
- 📌 优点:简单、进程间互不干扰
- 📌 缺点:某些进程页不够用频繁缺页,另一些进程页框可能被浪费
可变分配 + 局部置换
- 系统根据运行情况动态调整页框数
- 缺页时仍然只替换本进程的页
- 📌 优点:兼顾稳定性和效率,可结合工作集模型动态调整页框分配
可变分配 + 全局置换
- 页框数量可变,置换时可以选其他进程的页淘汰
- 📌 优点:全局命中率高,适合负载变化大的系统
- 📌 缺点:进程间存在强干扰,容易产生抖动(Thrashing)
为什么没有“固定分配 + 全局置换”?
- 固定分配要求进程页框数量固定不可变
- 全局置换意味着页框会被别的进程抢走,页框数变了 ➜ 和“固定”矛盾
📌 所以“固定分配 + 全局置换”逻辑上冲突,不存在
物理块调入算法
- 平均分配算法
- 按比例分配算法:按照进程大小按比例
- 优先权分配算法:重要紧迫的进程分配多
调入页面的时机
- 预调页策略:预测之后可能被访问的页面,将它们预先调入内存
- 请求调页策略:进程在运行中需要访问的页面不在内存,提出请求
从何处调入页面
- 系统拥有足够的对换区空间:文件全部存放对换区
- 系统缺少足够的对换区空间:将不会被修改的文件放文件区,可能被修改的部分换出时放在对换区
- UNIX方式:曾今运行过但被换出的页面放在对换区
页面置换算法
1.最佳置换算法(OPT)
选择淘汰以后永远不使用的页面,或是在最长时间内不再被访问的页面
2.先进先出页面置换算法(FIFO)
选择淘汰最早进入内存的页面
Belady异常:分配的物理块增多,缺页次数不减反增的异常现象,只有FIFO算法可能出现
3.最近最久未使用置换算法(LRU)
选择淘汰最近最长时间未使用的页面
该算法为每个页面设置一个访问字段,记录页面自上次被访问所经历的时间
4.时钟置换算法(CLOCK)
(1)简单的CLOCK置换算法(也称最久未用算法(NRU))