现代操作系统:内存管理(二)
4.2 A Memory Abstraction: Address Spaces内存抽象:地址空间
4.2.1 The Notion of an Address Space地址空间的概念
正如进程概念创建了一种抽象的CPU来运行程序(每个进程都被认为是唯一在运行的进程),地址空间创建了一种抽象的内存来运行程序。
地址空间用于进程,就像连接器用于模块一样。也就是说,地址空间允许每个进程相信它有自己的从地址0开始的内存(也就是虚拟内存)。
Base and Limit Registers基址寄存器与界限寄存器
基址寄存器和界限寄存器是附加的硬件,对程序员来说是不可见的,它通过在运行时访问每个地址时自动将基址(即基址寄存器中的值)添加到每个地址来支持多道编程。
此外,相对地址将与界限寄存器中的值进行比较,如果相对地址更大,进程将被中止,因为它已经超过了它的内存边界。将此与连接器Lab中的错误检查进行比较。
基址寄存器和界限寄存器是在进程启动时由操作系统设置的。
使用这两个寄存器就可以实现将每个进程的地址空间映射到物理内存的不同部分,即我们将程序运行时的基础物理地址保存在基址寄存器BR中,程序的长度加载到界限寄存器LR中,那么映射时当前进程程序计数器表示的下一条虚拟地址A对应的物理地址就是BR+A,如果BR+A>BR+LR则说明程序内存访问越界。
4.2.2 Swapping交换技术
在磁盘空间和内存空间中来回移动整个进程的过程称之为交换。
Multiprogramming with Variable Partitions变化分区下的多道编程
分区的数量和大小都会随着时间变化。
- MVT系统(multiprogramming with a varying number of tasks);
- 早期的PDP-10操作系统;
- 一个进程仍然只有一个片段,虚拟内存和物理内存都是连续的;
- 进程可以需要任意大小的内存,但是收到实际物理内存上限的限制;
- 进程使用的内存大小可以随时间变化;
- 进程可以移动(但可能被交换回不同的位置);
- 基址寄存器和界限寄存器的值在进程所需内存增加、减少或进程所在物理内存的地址移动时同步变化;
- 具有一个单一的就绪列表;
- 这是在程序运行时执行的动态地址转换;
- 必须对每个内存引用执行一次加法,实现虚拟地址向物理地址的转换;
- 使用的硬件被IBM称之为DAT(Dynamic Address Translation);
- 交换的过程消除了单个进程可能存在的内部碎片,内部碎片是进程中不能被使用的空间;
- 交换会引入外部内存碎片,即分配给进程的任何区域外的未被使用的内存空间;
- 上图中的3-4的过程称为memory compaction内存紧缩,即内存中没有足够大的连续空间来存放下一个进程时,可以对内存中当前存储的内容进行整理,减少其中的外部碎片(操作就是将所有的进程向下移动);但是这个操作的代价是昂贵的,一般不这样做;
- 交换的特性体现在:存在类似5-6和6-7展示的处理流程,将一个进程从内存空间中移除,然后将需要执行的进程从磁盘中加载入内存;
- 上述图中空洞区域不会比进程多两个,这是肯定的,因为一个进程一侧最多一个空洞,空洞之后就是下一个进程;
需要注意的是,进程所持有的内存通常是动态变化的,如果每个进程在创建时内存大小不变就是上面的情况,但实际情况是进程的数据段往往可以增长。那么在增长的情况下很有可能就会触及到别的进程的内存空间,如果产生了这种情况,就要找一块更大的内存空间用于存放该进程,或者将其他的一个或多个进程交换出去。如果一个进程在内存中不能增长且磁盘中的交换区已经满了,那么它就会被挂起直到有足够的空间。一般情况下为了防止上述操作的产生,我们会给每个进程开辟多一些额外的空间用于减少交换的次数。
Homework 22
3. A swapping system eliminates holes by compaction. Assume a random distribution of holes and data segments, assume the data segments are much bigger than the holes, and assume a time to read or write a 32-bit memory word of 4ns. About how long does it take to compact 4 GB? For simplicity, assume that word 0 is part of a hole and the highest word in memory conatains valid data.
一个具有交换功能的系统通过内存紧缩消除孔洞。假设孔和数据段随机分布且数据段比孔大得多,同时假设读或写一个32位存储空间的时间是4ns。那么内存紧缩到4gb大约需要多长时间?为了简单起见,假设字节0处于空闲区中,内存中最高的字节处包含有效数据。
读:32bit = 4Byte = 4ns è 1Byte = 1ns
写:32bit = 4Byte = 4ns è 1Byte = 1ns
4GB = 4 * 1024 * 1024 * 1024 Byte * 2ns = 8* 2^30 ns ≈ 8.79 s
4.2.3 Managing Free Memory空闲内存管理
The Placement Question位置问题?
Swapping交换(例如,MVT)引入了位置问题。也就是说,当几个空闲块足够大的时候,我们应该把这个进程放入哪个空闲块(分区)?
我们有几种不同的空闲区快选择方式,包括:最佳适配(Best Fit);最差适配(Worst Fit);首次适配(First Fit);快速适配(Quick Fit);下次适配(Next Fit)和Buddy系统。
- 首次适配:选择找到的第一个能放下当前进程的闲置内存块;
- 最佳适配:选择最小的可以放下当前进程的闲置内存块,似乎是最优解,但是代价非常大,因为即便找到了最适合的那个仍然会留下一定的内存碎片;
- 最差适配:选择最差适配就相当于每次都会找到内存中剩余的最大内存块来满足进程的需求,这种适配方式可以很快的填满所有的最大空闲内存块,且产生不可填入进程的内存块的概率小,但是后续需要进行内存紧缩;
- 快速适配:快速适配为那些常用大小的内存块维护单独的链表,比如先开辟一个指针数组,其中的第一项是4KB大小内存块的链表头,第二项是8KB大小内存块的链表头,然后一次是16KB,32KB等。
虽然上面的适配方式非常花里胡哨,但是我们一般使用的就是首次适配的方式,只要找到第一个足够大的可以容纳当前进程的空闲内存块即可。但是对首次适配进行一些改进就能得到下次适配,即从上一次停止的地方开始搜索。当我们找到第一个足够大的内存块时,我们将等同于目标进程大小的内存块分配给该进程,剩余的区域变为新的空闲内存块。
Homework 23
4. Consider a swapping system in which memory consists of the following hole sizes in memory order: 10MB, 4MB, 20MB, 18MB 7MB, 9MB, 12MB, and 15MB. Using first fit, which hole is taken for successive segment requests of
a. 12MB
b. 10MB
c. 9MB
Now repeat for best fit, worst fit, and next fit.
First Fit: a. 20MB b. 10MB c. 18MB.
Best Fit: a. 12MB; b. 10MB; c. 9MB.
Worst Fit: a. 20MB; b. 18MB; c. 15MB.
Next Fit:a. 20MB; b. 18MB; c. 9MB.
Implementing Free Memory实现空闲内存管理
Memory Management with Bitmaps使用位图的内存管理
将内存划分为块,并与每个块关联一个位,用于指示相应的块是空闲的还是已分配的。为了找到大小为N个块的块,需要找到N个表示空闲块的连续比特。比如有10MB的物理内存,我们将其划分为10个块,每个块1MB,那么只需要用10个bit来记录每个块的状态即可,0表示空,1表示被使用。
需要考虑的问题是:一个位代表多少内存呢?如果块的大小很大,那么被浪费的就很严重;如果很小,那用来存储内存状态的空间就很大。
Memory Management with Linked Lists使用链表的内存管理
相对于使用位图的方式,还不如使用一个节点链表,其中每个节点都对应着一个已经分配给进程的或仍处于空闲状态的内存块。
- 链表中的每一项给出了对应内存区域的长度和起始位置,并标注它是否已经被分配;
- 链表中的项不会从内存中取出供进程使用;
- 链表按照起始地址的顺序保存;
- 在释放内存时合并相邻的空闲内存块;
- 使用单链表或双链表;
- 类似于malloc/free的实现;
The Replacement Question替换问题
Swapping交换技术引入的一个问题就是如何进行交换,具体来说就是当我们需要更多闲置内存块时,哪个受害者进程会被选并交换出去;
这就是之前在进程调度中提及到的中期调度的部分,即从上方的短期调度三角形转移到下方挂起的两个状态的一个例子。
当我们在讨论demand paging(需求分页)的例子时我们会讲解在什么时候我们会从内存中移出一部分进程,同时将会尝试学习这个问题。
思考一下受害者进程的选择:
- 不能选择一个被pinned固定住的任务。举一个例子:这些进程的内存通常被绑定了,比如一个进程的DMA I/O正在被调度,那么这个进程将会被固定住直到DMA操作完成;
- 交换目标受害者的选择是中期调度的决定:如果一个进程已经被阻塞了很久,那么这个进程是一个很不错的候选进程;我们通常选择那些在内存中已经停留了更久的进程;
- 另一个问题是这个进程他会在挂起状态(被移出内存状态)持续多久;
- 对于需求分页技术,将一个页面交换出去的频率并不等同于将一个任务(进程)交换出去,选择一个受害者(被交换的进程或页面)是一个非常重要的内存管理决策,我们将在后面学习数个解决这个问题的原则与策略。
注:
- 现在的一些方案通常具有两个属性:每个任务都被连续的存储在内存中,因此每个任务在物理内存中的位置都是连续的;每个任务不能使用比当前系统中存在的内存更多的内存,因此每个进程的虚拟内存空间不能超过物理内存空间;
- Tanenbaum现在攻击了第二个因素,但是我希望两个都做并且从第一个开始;
- Tanenbaum(世界上绝大多数人)使用term paging作为demand paging的同义词,所以这很不幸的将两个概念混淆在了一起:i. Paging解决了替换问题并且基本上消除了外部碎片;ii. 需求获取,允许了所有已经被加载的任务的全部内存需求超过计算机的物理内存;
- 再说一遍term paging === demand paging,但是这是很不幸的:i. demand paging是一个细项并且是可描述的;ii. 虚拟内存应当被使用去和物理内存进行区分,目的是描述由虚拟内存向物理内存的转换。
posted on 2022-01-06 15:38 ThomasZhong 阅读(470) 评论(0) 编辑 收藏 举报