一、基本概念:地址重定位
1.1 需要了解的内容
程序装载到内存才可以运行
通常,程序可以执行文件格式保存在磁盘上多道程序设计模型
允许多个程序同时进入内存每个进程有自己的地址空间
一个进程执行时不能访问另一个进程的地址空间
进程不能执行不合适的操作
1.2 要解决的问题
说明:在左边的单处理器系统中,如果一个进程想要运行,那么必须将进程地址空间装载到物理内存中才可以运行。而右边的是多处理器系统中有多个进程需要进入物理内存执行,这里要解决的问题就是,如何将进程地址空间合理的装载到物理内存中,如何合理的分配使用内存,使得每个进程能正确执行。
1.3 复习:进程地址空间
1.4 注意
- 进程中的地址不是最终的物理地址
- 在进程运行前无法计算出物理地址
这就需要地址重定位来解决这些问题。
二、地址重定位
逻辑地址(相对地址、虚拟地址)
用户程序经过编译、汇编后形成目标代码,目标代码通常采用相对地址的形式,其首地址为0,其余地址都相对于首地址而编址。不能用逻辑地址在内存中读取信息。物理地址(绝对地址、实地址)
内存中存储单元的地址,可直接寻址
为了保证cpu
执行指令时可以正确访问内存单元,需要将用户程序中的逻辑地址转换为运行时可由机器直接寻址的物理地址,这一过程称为地址冲地位。
2.1 静态重定位与动态重定位
静态重定位
当用户程序加载到内存时,一次性实现逻辑地址到物理地址的转换。一般可由软件完成。动态重定位
在进程执行过程中进行地址变换,即逐条指令执行时完成地址转换。需要硬件部件支持,较为常用。
2.2 动态重定位实现
三、物理内存管理
3.1 空闲内存管理
说明:我们对物理内存有不同的划分,一种是等长的划分,一种是不等长的划分。
- 数据结构
1、位图
对于等长划分这种我们可以使用位图的方式。每个分配单元对应于位图中的一位,0
表示空闲,1
表示占用(或者相反)。对于不等长的划分可以使用下面两种分配结构。
2、空闲区表、已分配区表
表中每一项记录了空闲区(或已分配区)的起始地址、长度、标志
3、空闲块链表
3.2 内存分配算法
这里我们使用空闲区表、已分配区表为例来说明内存分配算法。
- 首次适配
first fit
在空闲区表中找到第一个满足进程要求的空闲区 - 下次适配
next fit
从上次找到的空闲区处接着查找 - 最佳适配
best fit
查找整个空闲区表,找到能够满足进程要求的最小空闲区 - 最差适配
worst fit
总是分配满足进程要求的最大空闲区
当找到满足进程需求的空闲区表后,需要将空闲区分为两部分,一部分供进程使用,另一部分形成新的空闲区。
3.3 回收问题
- 内存回收算法
- 当某一块归还后,前后空闲空间合并,修改内存空闲区表。
- 四种情况
上相邻、下相邻、上下都相邻、上下都不相邻
3.4 伙伴系统
这是Linux
底层内存管理采用的一种方法
- 一种经典的内存分配方案,是一种特殊的分离适配算法
- 主要思想:将内存按
2
的整数次幂进行划分,组成若干空闲块表;查找该链表找到能满足进程需求的最佳匹配块。 - 算法
- 首先将整个可用空间看作一块:
2^U
- 假设进程申请的空间大小为
s
,如果满足2^(U-1)<s<=2^U
,则分配整个块,否则,将块划分为两个大小相等的伙伴,大小为2^(U-1)
。 - 一直划分下去直到产生大于或等于
s
的最小块。
- 首先将整个可用空间看作一块:
3.5 伙伴系统例子
说明:从上图中可以看到上面的算法是如何工作的。
四、基本的内存管理方案1
即整个进程进入内存一片连续的区域,有多种解决方案:单一连续区、固定分区、可变分区、页式、段式、段页式等方案。
4.1 单一连续区
特点:一段时间内只有一个进程在内存中,有简单、内存利用率低的特点。这种方案是在早期系统中使用的,有三种不同的布局:
4.2 固定分区
- 把内存空间分割成若干个区域,称为分区
- 每个分区的大小可以相同也可以不同
- 分区大小固定不变
- 每个分区装一个且只能装载一个进程
说明:可以看到不同的进程链分别排在不同的分区位置。这样有个缺点是有的进程链很长,一时半会得不到分区,但是此时可能有些空闲分区根本没有被使用。于是还有右边这种排队方案,就是只有一个进程链,然后哪个分区空闲了,排在首位的进程就进入执行。早期手机中就是采用这种方法。
4.3 可变分区
- 根据进程的需要,把内存空闲空间分割出一个分区,分配给该进程
- 剩余部分称为新的空闲区
- 会导致一些问题:导致一些外碎片(很小的空闲内存无法利用),这样会导致内存利用率下降。
碎片问题解决
- 碎片:很小的、不易利用的空闲区,导致内存利用率下降
- 解决方案:紧缩技术
在内存中移动程序,将所有小的空闲区合并为较大的空闲区。又称为压缩技术,紧致技术,搬家技术 - 紧缩时要考虑的问题
系统开销、移动时机
五、基本内存管理方案2
即一个进程进入内存中若干个不连续的区域
5.1 页式存储管理方案
-
设计思想
-
用户进程地址空间被划分为大小相等的部分,称为页(
page
)或页面,从零开始编号。这是逻辑地址空间上的称谓。 - 内存空间按同样大小划分为大小相等的区域,称为页框(
page frame
),从零开始编号;也称为物理页面,页帧,内存块 - 内存分配(规则)
以页为单位进行分配,并按进程需要的页数来分配;逻辑上相邻的页,物理上不一定相邻。 - 典型的页面尺寸:
4K
或4M
-
用户进程地址空间被划分为大小相等的部分,称为页(
-
逻辑地址
说明:逻辑地址分为页号和页内地址(页内偏移),这种划分是系统自动完成的,对用户是透明的。 -
内存分配
说明:可以看到连续的进程地址空间映射到页帧中的物理内存是杂乱的。
说明:对于逻辑地址空间和物理内存空间的杂乱的映射,如何进行映射呢?这里我们需要使用页表来记录这种映射。
相关数据结构及地址转换
-
页表
- 由若干页表项(记录了逻辑页号与页框号对应关系)构成
- 每个进程一个页表,存放在内存
- 页表起始地址保存在何处?
空闲内存管理
其实我们可以使用位图就可以管理物理内存了地址转换(硬件支持)
cpu
取到逻辑地址,自动划分为页号和页内地址;用页号查页表,得到页框号,再与页内偏移拼接成物理地址。在这种方案中我们也会遇到碎片问题,但是这里的碎片是内碎片。比如某个进程需要5
页加一条指令,于是这里我们需要分配6
页给这个进程。
5.2 段式存储管理方案
-
设计思想
- 用户进程地址空间:按程序自身的逻辑关系划分为若干个程序段,每个段都有一个段名
- 内存空间被动态划分为若干长度不相同的区域,称为物理段,每个物理段由起始地址 和长度确定。
- 内存分配(规则):以段为单位进行分配,每段在内存中占据连续空间,但各段之间可以不相邻。其实就是将程序分为若干段,每段占用一块内存空间。
-
逻辑地址
说明:和页式类似,逻辑地址分为段号和段内地址。不同的是段号和段内地址不是自动划分的。我们看一个例子:
说明:同样的,和页式类似,每个段的位置都不一样或不连续。而我们这里使用段表来将逻辑段号和物理内存映射起来。其中段表包含长度和段起始地址。
相关数据结构及地址转换
段表
每项记录了段号,段首地址和段长度之间的关系
每个进程一个段表,存放在内存
段表起始地址保存在何处?物理内存管理
我们可以使用不等长的分配方案进行管理地址转换(硬件)
cpu
取到逻辑地址,用段号查段表,得到该段在内存的起始地址,与段内偏移地址计算出物理地址
5.3 段页式存储管理方案
产生背景
综合页式、段式方案的优点,克服二者的缺点-
设计思想
用户进程划分:先按段划分,每一段按页面划分
逻辑地址:
内存划分:同页式存储管理方案
内存分配:以页为单位进行分配 数据结构及有关操作
段表:记录了每一段的页表起始地址和页表长度
页表:记录了逻辑页号与页框号对应关系,每一段有一张页表,一个进程有多个页表
空闲区管理:同页式管理
内存分配、回收:同页式管理地址转换
由硬件支持
5.4 小结
六、交换技术
6.1 内存不足时如何管理
即如何在一个较小的物理内存空间中运行一个会占用较大地址空间的进程?
6.2 内存“扩充”技术
- 内存紧缩技术(例如:可变分区。即有时候可以使用内存紧缩技术来满足进程所需内存),但是这种技术一般不能解决问题
- 覆盖技术(
overlaying
) - 交换技术(
swapping
) - 虚拟存储技术(
virtual memory
)
6.3 覆盖技术
- 解决问题:程序大小超过物理内存总和
- 程序执行过程中,程序的不同部分在内存中相互替代。
- 按照其自身的逻辑结构,将那些不会同时执行的程序段共享同一块内存区域
- 要求程序各模块之间有明确的调用结构
- 程序员声明覆盖结构,操作系统完成自动覆盖
这种技术主要用于早期的操作系统,现在使用不多。
6.4 交换技术
设计思想
内存空间紧张时,系统将内存中某些进程暂时移动到外存,把外存中某些进程交换进内存,占据前者所占用的区域(进程在内存与磁盘之间的动态调用)。讨论:实现时遇到的问题
进程的哪些内容要交换到磁盘?会遇到什么困难?
在磁盘的什么位置保存被换出的进程?
交换时机?
如何选择被换出的进程?
如何处理进程空间增长?哪些内容要交换到磁盘?会遇到什么困难?
1、运行时创建或修改的内容:栈和堆
2、交换区:一般系统会指定一块特殊的磁盘区域作为交换空间,包含连续的磁道,操作系统可以使用底层的磁盘读写操作对其高效访问。
3、何时需要发生交换?只要不用就换出;内存空间不够或有不够的危险时换出,一般与调度器结合使用
4、考虑进程的各种属性;不应换出处于等待I/O
状态的进程-
进程空间增长的困难及解决
说明:这里给出了两种解决方案,一种是左边的为栈预留一部分空间;一种是右边的让数据区和栈去同向增长,即在一个预留区中增长。