1
0
mirror of https://github.com/Didnelpsun/CS408.git synced 2026-02-11 14:45:57 +08:00

更新内存管理

This commit is contained in:
Didnelpsun
2021-08-23 23:55:06 +08:00
parent ddd6900ba6
commit c3d4acdf8f
3 changed files with 283 additions and 46 deletions

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,2 @@
# 内存管理习题

View File

@@ -1,19 +1,29 @@
# 内存管理
## 内存管理概念
## 普通内存管理
### 内存管理基础知识
#### 内存
#### 内存概念
+ 内存是用于存放数据的硬件。程序执行前需要先放到内存中才能被CPU处理用于缓冲速度。
+ 内存地址从0开始,每个地址对应一个存储单元。
+ 内存是用于存放数据的硬件。程序执行前需要先放到内存中才能被$CPU$处理用于缓冲速度。
+ 内存地址从$0$开始,每个地址对应一个存储单元。
+ 存储单元的大小不定:
+ 按字节编址则每个存储单元大小为1B八个二进制位。
+ 按字编址每个存储单元大小为一个字根据计算机的字长确定大小若字长为16位则一个字大小为16个二进制位。
+ 相对地址又称逻辑地址,绝对地址又称物理地址。编译时只考虑逻辑地址,实际放入内存再考虑物理地址。
+ 按字节编址,则每个存储单元大小为$1B$,八个二进制位。
+ 按字编址,每个存储单元大小为一个字,根据计算机的字长确定大小,若字长为$16$位,则一个字大小为$16$个二进制位。
#### 程序运行过程
#### 内存管理功能
1. 操作系统负责内存空间的分配与回收。
2. 操作系统需要提供某种技术从逻辑上对内存空间进行扩充。
3. 操作系统需要提供地址转换功能,负责程序的逻辑地址与物理地址的转换。
+ 相对地址(逻辑地址):从$0$号开始,程序员只用知道逻辑地址,可有相同逻辑地址。
+ 绝对地址(物理地址):内存物理单元的集合,是地址转换的最终地址。从逻辑地址到物理地址就是**地址重定位**。
4. 操作系统需要提供内存保护功能。保证各进程在各自存储空间内运行,互不干扰:
+ 在$CPU$中设置一对上、下限寄存器,存放进程的上、下限地址。进程的指令要访问某个地址时,$CPU$检查是否越界。
+ 采用重定位寄存器(又称基址寄存器,用于地址相加)和界地址寄存器(又称限长寄存器,用于地址比较)进行越界检查。重定位寄存器中存放的是进程的起始物理地址。界地址寄存器中存放的是进程的最大逻辑地址。
#### 程序载入过程
+ 程序运行过程:
1. 编译:由编译程序将用户源代码编译成若干个目标模块(编译就是把高级语言翻译为机器语言)。
@@ -28,23 +38,14 @@
+ 绝对装入只适用于单道程序环境。
+ 程序中使用的绝对地址,可在编译或汇编时给出,也可由程序员直接赋予。
+ 通常情况下都是编译或汇编时再转换为绝对地址。
2. 静态重定位(可重定位装入)(多道批处理操作系统):编译、链接后的装入模块的地址都是从0开始的,指令中使用的地址、数据存放的地址都是相对于起始地址而言的逻辑地址。可根据内存的当前情况,使用单独的装入程序将装入模块装入到内存的适当位置。装入时对地址进行“重定位”,将逻辑地址变换为物理地址(地址变换是在装入时一次完成的)。
2. 静态重定位(可重定位装入)(多道批处理操作系统):编译、链接后的装入模块的地址都是从$0$开始的,指令中使用的地址、数据存放的地址都是相对于起始地址而言的逻辑地址。可根据内存的当前情况,使用单独的装入程序将装入模块装入到内存的适当位置。装入时对地址进行“重定位”,将逻辑地址变换为物理地址(地址变换是在装入时一次完成的)。
+ 静态重定位的特点是在一个作业装入内存时,必须分配其要求的全部内存空间,如果没有足够的内存,就不能装入该作业。
+ 作业一旦进入内存后,在运行期间就不能再移动,也不能再申请内存空间。
3. 动态重定位(动态运行时装入)(现代操作系统):编译、链接后的装入模块的地址都是从0开始的。装入程序把装入模块装入内存后,并不会立即把逻辑地址转换为物理地址,而是把地址转换推迟到程序真正要执行时才进行。因此装入内存后所有的地址依然是逻辑地址。这种方式需要一个重定位寄存器的支持。
3. 动态重定位(动态运行时装入)(现代操作系统):编译、链接后的装入模块的地址都是从$0$开始的。装入程序把装入模块装入内存后,并不会立即把逻辑地址转换为物理地址,而是把地址转换推迟到程序真正要执行时才进行。因此装入内存后所有的地址依然是逻辑地址。这种方式需要一个重定位寄存器的支持。
+ 采用动态重定位时允许程序在内存中发生移动。
+ 可将程序分配到不连续的存储区中:在程序运行前只需裂入它的部分代码即可投入运行,然后在程序运行期间,根据需要动态申请分配内存。
+ 便于程序段的共享,可以向用户提供一个比存储空间大得多的地址空间。
#### 内存管理功能
1. 操作系统负责内存空间的分配与回收。
2. 操作系统需要提供某种技术从逻辑上对内存空间进行扩充。
3. 操作系统需要提供地址转换功能,负责程序的逻辑地址与物理地址的转换。
4. 操作系统需要提供内存保护功能。保证各进程在各自存储空间内运行,互不干扰:
+ 在CPU中设置一对上、下限寄存器存放进程的上、下限地址。进程的指令要访问某个地址时CPU检查是否越界。
+ 采用重定位寄存器(又称基址寄存器)和界地址寄存器(又称限长寄存器)进行越界检查。重定位寄存器中存放的是进程的起始物理地址。界地址寄存器中存放的是进程的最大逻辑地址。
### 内存空间分配回收
分为:
@@ -63,15 +64,15 @@
+ 内部碎片,分配给某进程的内存区域中,如果有些部分没有用上。
+ 外部碎片,是指内存中的某些空闲分区由于太小而难以利用。
#### 单一连续分配
#### 单一连续分配
+ 内存被分为系统区和用户区。系统区通常位于内存的低地址部分,用于存放操作系统相关数据:用户区用于存放用户进程相关数据。
+ 内存被分为系统区和用户区。系统区通常位于内存的低地址部分,用于存放操作系统相关数据用户区用于存放用户进程相关数据。
+ 内存中只能有一道用户程序,用户程序独占整个用户区空间。
+ 优点:
+ 实现简单。
+ 无外部碎片。
+ 可以采用覆盖技术扩充内存。
+ 不一定需要采取内存保护如早期的PC操作系统Ms-Dos
+ 因为只有一道程序,所以肯定不会访问越界,不一定需要采取内存保护(如早期的$PC$操作系统$Ms-Dos$)。
+ 缺点:
+ 只能用于单用户、单任务的操作系统中。
+ 有内部碎片。即分配给某进程的内存区域中,如果有些区域没有用上的部分
@@ -82,8 +83,8 @@
+ 将整个用户空间划分为若干个固定大小的分区,在每个分区中只装入一道作业。
+ 分区的方式:
+ 分区大小相等:缺乏灵活性,但是很适合用于用一台计算机控制多个相同对象的场合。
+ 分区大小不等:增加了灵活性,可以满足不同大小的进程需求。根据常在系统中运行的作业大小情况进行划分(比如:划分多个小分区、适量中等分区、少量大分区)。
+ 记录分区的方法:操作系统需要建立一个数据结构——分区说明表,来实现各个分区的分配与回收。每个表项对应一个分区,通常按分区大小排列。每个表项包括对应分区的天小、起始地址、状态(是否已分配)。
+ 分区大小不等:增加了灵活性,可以满足不同大小的进程需求。根据常在系统中运行的作业大小情况进行划分(比如划分多个小分区、适量中等分区、少量大分区)。
+ 记录分区的方法:操作系统需要建立一个数据结构——**分区说明表**,来实现各个分区的分配与回收。每个表项对应一个分区,通常按分区大小排列。每个表项包括对应分区的天小、起始地址、状态(是否已分配)。
+ 分区分配过程:当某用户程序要装入内存时,由操作系统内核程序根据用户程序大小检索该表,从中找到一个能满足大小的、未分配的分区,将之分配给该程序,然后修改状态为“己分配”。
+ 优点:
+ 实现简单。
@@ -109,42 +110,60 @@
动态分区分配算法,为了解决动态分区分配方式中如何从多个空闲分区中选择一个分区分配:
1. 首次适应算法First Fit
1. 首次适应算法($First\,Fit$
+ 算法思想:每次都从低地址开始查找,找到第一个能满足大小的空闲分区。
+ 如何实现:空闲分区以**地址**递增的次序排列。每次分配内存时顺序查找空闲分区链(或空闲分区表),找到大小能满足要求的第一个空闲分区。
+ 优点:
+ 首次适应算法每次都要从头查找,每次都需要检索低地址的小分区。但是这种规则也决定了当低地址部分有更小的分区可以满足需求时,会更有可能用到低地址部分的小分区,也会更有可能把高地址部分的分区保留下来。
+ 首次适应算法每次都要从头查找,每次都需要检索低地址的小分区。但是这种规则也决定了当低地址部分有更小的分区可以满足需求时,会更有可能用到低地址部分的小分区,也会更有可能把高地址部分的分区保留下来。
+ 算法开销小,每次分区后不需要对分区队列重新排序。
2. 最佳适应算法Best Fit
+ 缺点
+ 造成低分区大量内存碎片。
+ 都要重复经过已经分配的底层区间,增加查找开销。
2. 最佳适应算法($Best\,Fit$
+ 算法思想:由于动态分区分配是一种连续分配方式,为各进程分配的空间必须是连续的一整片区域。因此为了保证当“大进程”到来时能有连续的大片空间,可以尽可能多地留下大片的空闲区,即,优先使用更小的空闲区。
+ 如何实现:空闲分区按**容量**递增次序链接。每次分配内存时顺序查找空闲分区链(或空闲分区表),找到大小能满足要求的第一个空闲分区。当分配完后需要重新调整空闲分区链(或空闲分区表)。
+ 优点:容易保存大分区。
+ 缺点:
+ 每次都选最小的分区进行分配,会留下越来越多的、很小的、难以利用的内存块。因此这种方法会产生很多的外部碎片且很难查找回收。
+ 算法开销大,每次分区外需要对分区队列进程重新排序。
3. 最坏适应算法Worst Fit或最大适应算法Largest Fit
3. 最坏适应算法($Worst\,Fit$)或最大适应算法($Largest\,Fit$
+ 算法思想:为了解决最佳适应算法的问题――即留下太多难以利用的小碎片,可以在每次分配时优先使用最大的连续空闲区,这样分配后剩余的空闲区就不会太小,更方便使用。
+ 如何实现:空闲分区按**容量**递减次序链接。每次分配内存时顺序查找空闲分区链(或空闲分区表),找到大小能满足要求的第一个空闲分区。当分配完后需要重新调整空闲分区链(或空闲分区表)。
+ 优点:可用减少难以利用的小碎片。
+ 缺点:
+ 每次都选最大的分区进行分配,虽然可以让分配后留下的空闲区更大,更可用,但是这种方式会导致较大的连续空闲区被迅速用完。如果之后有“大进程”到达,就没有内存分区可用了。
+ 算法开销大,每次分区外需要对分区队列进程重新排序。
4. 临近适应算法Next Fit
4. 临近适应算法($Next\,Fit$
+ 算法思想:首次适应算法每次都从链头开始查找的。这可能会导致低地址部分出现很多小的空闲分区,而每次分配查找时,都要经过这些分区,因此也增加了查找的开销。如果每次都从上次查找结束的位置开始检索,就能解决上述问题。
+ 如何实现:空闲分区以地址递增的顺序排列(可排成一个循环链表)。每次分配内存时从上次查找结束的位置开始查找空闲分区链(或空闲分区表),找到大小能满足要求的第一个空闲分区。
+ 优点:减少了检索空闲分区的次数,提高了效率。
+ 缺点:邻近适应算法的规则可能会导致无论低地址、高地址部分的空闲分区都有相同的概率被使用,也就导致了高地址部分的大分区更可能被使用,划分为小分区,最后导致无大分区可用。
所以综合来看,首次适应算法效果最好就
所以综合效果来看,首次适应算法>最佳适应法?临近适应法>最大适应法
首次适应法和临近适应法只用简单查找,最佳适应法和最大适应法都需要对可用块进行排序和遍历。
#### 基本分页存储管理
+ 将内存空间分为一个个大小相等的分区比如每个分区4KB每个分区就是一个“页框”或称“页帧”、“内存块”、“物理块”。每个页框有一个编号即“页框号”或者“内存块号”、“页帧号”、“物理块号”页框号从0开始。
+ 将用户进程的地址空间也分为与页框大小相等的一个个区域称为“页”或“页面”。每个页面也有一个编号即“页号”页号也是从0开始。所以页面不同于页框是进程的逻辑概念。进程的最后一个页面可能没有一个页框那么大。因此页框不能太大否则可能产生过大的内部碎片
分页:
+ 将内存空间分为一个个大小相等的分区(比如每个分区$4KB$),每个分区就是一个“页框”($Page\,Frame$),或称“页帧”、“内存块”、“物理块”。每个页框有一个编号,即“页框号”(或者“内存块号”、“页帧号”、“物理块号”)页框号从$0$开始。
+ 将用户进程的地址空间也分为与页框大小相等的一个个区域,称为“页”($Page$)或“页面”。每个页面也有一个编号,即“页号”,页号也是从$0$开始。所以页面不同于页框,是进程的逻辑概念。(进程的最后一个页面可能没有一个页框那么大。)
+ 页框不能太大,否则可能产生过大的内部碎片,也不能太小,否则回页面数过大,页表过长占用内存,同时增加硬件地址转换的开销,降低页面换入换出的效率。
+ 外存中也同样的单位进行划分,直接称为“块”($Block$)。
+ 操作系统以页框为单位为各个进程分配内存空间。进程的每个页面分别放入一个页框中。也就是说,进程的页面与内存的页框有一一对应的关系。
+ 各个页面不必连续存放,也不必按先后顺序来,可以放到不相邻的各个页框中。
+ 为了方便计算页号、页内偏移量、页面大小一般设为的整数幂。
+ 如果每个页面大小为$2^k$B用二进制数表示逻辑地址则末尾k位即为页内偏移量,其余部外就是页号
+ 为了方便计算页号、页内偏移量、页面大小一般设为$2$的整数幂。
+ 如果每个页面大小为$2^kB$,用二进制数表示逻辑地址,则末尾$k$位即为页内偏移量,其余部外就是页号
地址结构:
+ 分为页面偏移量$W$和页号$P$两个部分。
+ 长度为$32$位,$0\sim11$是页内地址,即页内偏移量,每页大小为$4KB$。
+ $12\sim31$为页号,代表每个进程内的页的顺序,地址空间最多允许$2^{20}$页。
页表:
+ 因为允许将进程的各个页离散地存储在内存不同的物理块中,但系统应能保证进程的正确运行,即能在内存中找到每个页面所对应的物理块,所以为了能知道进程的每个页面在内存中存放的位置,操作系统要为每个进程建立一张页表,其中页表大小也与页面一样被页框约束。
+ 一个进程对应一张页表。
+ 进程的每一页对应一个页表项。
@@ -161,7 +180,7 @@
深入来看因为每页表项会顺序连续存储在内存中若该页表在内存中存放的起始地址是X则M号页对应的页表项存放在内存地址X+3×M。
同时因为页面大小为4KB所以每个页框即可用存放的最大值大小为4*1024÷3=1365个页表项但是此时会余下4×1024÷3=1B页内碎片,所以一定会在中间空出1B内存所以1365号页在页框约束下会在新的下一个页框存储表项会存放在X+3×1365+1处。这时候地址公式就不管用了。
同时因为页面大小为4KB所以每个页框即可用存放的最大值大小为4*1024÷3=1365个页表项但是此时会余下4×1024÷3=$页内$碎片,所以一定会在中间空出$内存$所以1365号页在页框约束下会在新的下一个页框存储表项会存放在X+3×1365+1处。这时候地址公式就不管用了。
而如果每个页表项占4字节则每个页框刚好能放下1024个页表项从而没有余数能减少查找的麻烦。
@@ -169,7 +188,7 @@
#### 基本地址变换机构
可用借助页表进行转换通常会在系统中设置一个页表寄存器PTR存放页表在内存中的起始地址F和页表长度M即这个进程里有多少页。进程未执行时页表的始址和页表长度放在进程控制块PCB当进程被调度时操作系统内核会把它们放到页表寄存器中。
可用借助页表进行转换通常会在系统中设置一个页表寄存器PTR存放页表在内存中的起始地址F和页表长度M即这个进程里有多少页。进程未执行时页表的始址和页表长度放在进程控制块$PCB$)中,当进程被调度时,操作系统内核会把它们放到页表寄存器中。
在页式存储管理的系统中时,只用确定页面大小和逻辑结构就能得到物理地址。
@@ -203,7 +222,7 @@
+ 由于查询快表的速度比查询页表的速度快很多,因此只要快表命中,就可以节省很多时间。
+ 因为局部性原理一般来说快表的命中率可以达到90%以上。
+ 快表的地址变换过程:
1. CPU给出逻辑地址由某个硬件算得页号、页内偏移量将页号与快表中的所有页号进行比较。
1. $CPU$给出逻辑地址,由某个硬件算得页号、页内偏移量,将页号与快表中的所有页号进行比较。
2. 如果找到匹配的页号(即命中),说明要访问的页表项在快表中有副本,则直接从中取出该页对应的内存块号,再将内存块号与页内偏移量拼接形成物理地址,最后,访问该物理地址对应的内存单元。因此,若快表命中,则访问某个逻辑地址仅需一次访存即可。
3. 如果没有找到匹配的页号,则需要访问内存中的页表,找到对应页表项,得到页面存放的内存块号,再将内存块号与页内偏移量拼接形成物理地址,最后,访问该物理地址对应的内存单元。同时将其存入快表,以便后面可能的再次访问。但若快表已满,则必须按照一定的页面置换算法对旧的页表项进行替换。因此,若快表未命中,则访问某个逻辑地址需要两次访存。
@@ -227,7 +246,7 @@
地址转换过程:
1. 按照地址结构将逻辑地址拆分成三部分。
2. 从PCB中读出页目录表始址再根据一级页号查页目录表找到下一级页表在内存中的存放位置。
2.$PCB$中读出页目录表始址,再根据一级页号查页目录表,找到下一级页表在内存中的存放位置。
3. 根据二级页号查表,找到最终想访问的内存块号。
4. 结合页内偏移量得到物理地址。
@@ -320,6 +339,8 @@
2. 交换技术。
3. 虚拟存储技术。
前两种技术不是重点。
#### 覆盖技术
覆盖技术在同一个程序或进程中执行。
@@ -338,14 +359,16 @@
交换技术在不同进程或作业之间进行的。
+ 交换(对换)技术的设计思想:内存空间紧张时,系统将内存中某些进程暂时换出外存,把外存中某些已具备运行条件的进程换入内存(进程在内存与磁盘间动态调度)。
+ 交换的位置:具有对换功能的操作系统中,通常把磁盘空间分为文件区和对换区两部分。文件区主要用于存放文件,主要追求存储空间的利用率,因此对文件区空间的管理采用离散分配方式;对换区空间只占磁盘空间的小部分被换出的进程数据就存放在对换区。由于对换的速度直接影响到系统的整体速度因此对换区空间的管理主要追求换入换出速度因此通常对换区采用连续分配方式学过文件管理章节后即可理解。总之对换区的I/O速度比文件区的更快。
+ 交换的位置:具有对换功能的操作系统中,通常把磁盘空间分为文件区和对换区两部分。文件区主要用于存放文件,主要追求存储空间的利用率,因此对文件区空间的管理采用离散分配方式;对换区空间只占磁盘空间的小部分,被换出的进程数据就存放在对换区。由于对换的速度直接影响到系统的整体速度,因此对换区空间的管理主要追求换入换出速度,因此通常对换区采用连续分配方式(学过文件管理章节后即可理解)。总之,对换区的$I/O$速度比文件区的更快。
+ 交换的时机:交换通常在许多进程运行且内存吃紧时进行,而系统负荷降低就暂停。例如在发现许多进程运行时经常发生缺页,就说明内存紧张,此时可以换出一些进程;如果缺页率明显下降、就可以暂停换出。
+ 交换进程的选择:
+ 可优先换出阻塞进程。
+ 可换出优先级低的进程。
+ 为了防止优先级低的进程在被调入内存后很快又被换出,考虑进程在内存的驻留时间。
+ 暂时换出外存等待的进程状态是挂起状态。
+ 处理机调度的中级调度内存调度就是交换技术的实现。进程的PCB常驻内存。
+ 处理机调度的中级调度(内存调度)就是交换技术的实现。进程的$PCB$常驻内存。
覆盖用于同一个进程或程序中,二交换用于不同进程或作业之间。
## 虚拟内存管理
@@ -367,8 +390,8 @@
+ 若内存空间不够,由操作系统负责将内存中暂时用不到的信息换出到外存。
+ 在操作系统的管理下,在用户看来似乎有一个比实际内存大得多的内存,这就是虚拟内存。
+ 虚拟内存的最大容量是由计算机的地址结构CPU寻址范围确定的。
+ 虚拟内存的实际容量= min(内存和外存容量之和CPU寻址范围)。
+ 虚拟内存的最大容量是由计算机的地址结构($CPU$寻址范围)确定的。
+ 虚拟内存的实际容量= min(内存和外存容量之和,$CPU$寻址范围)。
+ 某计算机地址结构为32位按字节编址内存大小为512MB外存大小为2GB。则虚拟内存的最大容量为$2^{32}$B= 4GB而实际内存是2GB+512MB。
虚拟内存特征:
@@ -497,9 +520,9 @@
#### 改进型时钟置换算法
简单的时钟置换算法仅考虑到一个页面最近是否被访问过。事实上如果被淘汰的页面没有被修改过就不需要执行I/O操作写回外存。只有被淘汰的页面被修改过时才需要写回外存。
简单的时钟置换算法仅考虑到一个页面最近是否被访问过。事实上,如果被淘汰的页面没有被修改过,就不需要执行$I/O$操作写回外存。只有被淘汰的页面被修改过时,才需要写回外存。
因此除了考虑一个页面最近有没有被访问过之外操作系统还应考虑页面有没有被修改过。在其他条件都相同时应优先淘汰没有修改过的页面避免I/O操作。这就是改进型的时钟置换算法的思想。
因此,除了考虑一个页面最近有没有被访问过之外,操作系统还应考虑页面有没有被修改过。在其他条件都相同时,应优先淘汰没有修改过的页面,避免$I/O$操作。这就是改进型的时钟置换算法的思想。
需要利用到修改位,修改位=0表示页面没有被修改过修改位=1表示页面被修改过。
@@ -551,7 +574,7 @@
调入页面时机:
+ 预调页策略运行前根据局部性原理一次调入若干个相邻的页面可能比一次调入一个页面更高效。但如果提前调入的页面中大多数都没被访问过则又是低效的。因此可以预测不久之后可能访问到的页面将它们预先调入内存但目前预测成功率只有50%左右。故这种策略主要用于进程的首次调入,由程序员指出应该先调入哪些部分。
+ 请求调页策略运行时进程在运行期间发现缺页时才将所缺页面调入内存。由这种策略调入的页面一定会被访问到但由于每次只能调入一页而每次调页都要磁盘I/O操作因此I/O开销较大。
+ 请求调页策略(运行时):进程在运行期间发现缺页时才将所缺页面调入内存。由这种策略调入的页面一定会被访问到,但由于每次只能调入一页,而每次调页都要磁盘$I/O$操作,因此$I/O$开销较大。
调入页面位置: