操作系统——分页式内存管理


为什么要引入内存管理?
答:多道程序并发执行,共享的不仅仅只有处理器,还有内存,并发执行不过不进行内存管理,必将会导致内存中数据的混乱,以至于限制了进程的并发执行。

扩充内存的两种方式?
答:覆盖和交换技术是扩充内存的两种方法

1:覆盖技术。覆盖的基本思想是:由于程序运行时并非任何时候都需要访问程序和数据的各个部分(尤其对大程序而言),因此可以把用户空间分成一个固定区和若干个覆盖区。经常活跃的部分放在固定区,其余部分按照调用关系分配。首先将那些即将要访问的段放入覆盖区,其他段放在外存中,在需要调用之前,系统再将其调入覆盖区,替换覆盖区中原有的段。

特点:打破了必须将一个进程的全部信息装入主存后才能运行的限制,但是当同时运行的程序的代码量大于主存时仍不能允许,内存中常能更新的只有覆盖区的段

2:交换技术。交换的基本思想是:把处于等待状态的程序从内存移到辅存,把内存空间腾出来,这一过程被称为换出;把准备好竞争CPU运行的而程序从辅存移到主存,这一过程称为换入。

特点:交换技术主要是在不同的进程之间进行,覆盖则是用于同一个进程。

连续内存分配管理
答:连续分配方式,指为一个用户分配一个连续的内存空间。包括:

1:单一连续分配。内存此时分为系统区和用户区,系统区只分配给操作系统使用,通常在低地址部分;用户区为用户提供。内存中只有一道程序,也无需进行内存保护。无外部碎片但是有内部碎片,且存储器效率低下

2:固定分区分配。将内存空间划分为若干个固定大小的区域,每个分区只能装入一道作业。当有空闲分区时,便可以再从外存的后备作业队列中,选择适当大小的作业装入该区,分为(分区大小相等和分区大小不相等两种方式)无外部碎片但是有内部碎片(分区内部有空间的浪费),且存储器效率低下,但是可存在多道程序,是用于多道程序并发执行的最简单的内存分配方式。

3:动态分区分配。也成为可变分区分配,它不预先对内存进行划分,而是在进程装入内存时,根据进程的大小动态的建立分区,并使分区的大小正好适合进程的需要,其分区的数目和大小是可变的。但是随着时间的推移,很容易产生外部碎片(区域1进程释放后20M(区域1),区域2中19M仍在 ,再进入14M,放在区域一原来的地方,进程间的内存空间被浪费6M),外部碎片指的是分区以外的存储空间被浪费

解决问题1:为了解决外部碎片的问题,可以使用“紧凑”技术来解决:操作系统不时的对进程进行移动和整理(需要动态重定位寄存器的支持,较为费时)

解决问题2:动态分区的分配问题,

1:首次适应算法,空闲分区以地址递增的方式链接,分配内存时顺序查找,找到大小满足要求的第一个空闲分区

通常该算法是最快最好的也是最简单的。

2:最佳适应算法,空闲分区以容量递增形成分区链,找到第一个满足要求的空闲分区

实际上新能不佳,因为每次最佳分配通常会留下很小的难以利用的内存块,产生外部碎片。

3:最坏适应算法,又称最大适应算法,空闲分区以容量递减形成分区链,找到第一个满足要求的空闲分区,也就是挑选出最大的分区

性能较差,因为算法开销也是需要考虑的一部分

4:邻近适应算法,又称循环首次适应算法,也就是从首次适应算法中演变而来,不同的是,从上次查找结束的位置开始继续查找

性能较差

非连续内存分配管理
答:根据分区的大小是否固定主要分为分页和分段的存储管理方式

非连续分配允许一个程序分散的装入到不相邻的内存分区中,这需要额外的空间去存储它们的存储区索引,使得非连续分配方式的存储密度低于连续存储方式

1.分页式存储管理方式
分页式存储管理方式,根据运行时是否需要把作业的所有页面都装入内存才能运行分为基本分页存储管理方式和请求分页存储管理方式

@基本分页式存储管理方式

答:在连续存储管理方式中,固定分区会产生内部碎片,动态分区会产生外部碎片。这两种技术对内存的利用率都比较低,分页:把主存空间划分为大小相等且固定的块,块相对较小,作为主存的基本单位,每个进程也以块为基本单位划分,进程在执行时,以块为单位逐个申请主存中的块空间。

分析:从形式上来看,很像固定分区,但却有着本质的不同点:1:块的大小相对于分区来说要小得多 2:进程也按照块来划分,运行时按照块来申请主存,尽管这样也会产生内部碎片,但是相对于进程的大小来说是非常小的,每个进程平均只产生半个块大小的内部碎片

基本概念
进程中的块称为页。

主存中的块称为页框。

外存也以同样的单位进行划分,也称为块。

进程执行时,向主存申请块,就产生了页与页框的一一对应关系

为方便地址转换,页面的大小应该是2的整次幂,页面的大小也应该适中,太小的话回使得进程的页面数过多,页表过长,占用大量的内存且增加硬件地址转换的开销,降低页面的换入/换出效率。过大会使得页内碎片增大,降低内存的利用率。所以空间效率和时间效率都应该被考虑在内。

(逻辑地址)地址结构:包含两部分,第一部分为页号P,后一部分为页内偏移量W,地址长度为32位,其中0~11位为页内地址,即每页大小为4 KB,12~31位为页号,地址空间最多允许有2的30次方页。(二进制与十进制之间的转换)

页表:为了便于在内存中找到进程的每个页面对应的物理块,系统为每个进程建立了一张页表,记录页面在内存中对应的物理块号,页表一般存在内存中。页表的第一部分存的是页号,第二部分存的是物理内存中的块号,页表项的第二部分与地址的第二部分共同组成物理地址。

基本地址变换机构
地址变换机构的任务是将逻辑地址转换为内存中的物理地址,地址变换是借助于页表实现的(注意十进制与二进制的转换)地址空间为一维。

第一步:根据逻辑地址计算逻辑地址(页号 * 页长 + 偏移地址)中的页号(P = A/L)和地址偏移量(W = A %L)

逻辑地址A = 2500 B,页面大小(块的大小) L = 1 KB, 得到 p = 2, W = 452

第二步:比较页号P和页表长度M,若P > M,则产生越界中断,否则继续执行

第三步:页表寄存器中,分为两部分(页表起始地址F和页表长度M),计算页号P在页表中对应的物理地址的页表项地址(对应块号b) p = 页表起始项F +页号P * 页表项长度,得到物理块号,直接对应的2页号对应块号8(页号与块号在页表中有直接对应),注意:页表长度:指的是一共有多少页。页表项长度:指的是一页占多大内存。

第四步:计算物理地址E = b L +W (块号 块大小+地址偏移量)得到E = 8 * 1 KB +452 B = 8644 B ,得到物理空间之后,就可以访问内存了。

页表项大小的确定
以32位逻辑地址为例,字节为编码单位,一个页面的大小为4 KB,所以2的32次方 B 除以4 KB地址空间一共有 1 M 页,则需要log 2 (1 M) = 20 位才能保证表示范围能容纳所有的页面,又以字节为编码单位,[20 / 8] = 3 B,所以页表项的大小应该大于等于3 B,取4 B为常见。

将页表始址与页号和页表项长度的乘积相加,便得到该表项在页表中的位置,

于是可从中得到该页的物理块号,将之装入物理地址寄存器中。

列出式子出来: 页表始址+页号x页表项长度

1)页表项长度是页面长度是吗?

2)如果是页面长度,那两者相乘就是整个内存的大小来,你想一想整个内存都用来存储页表可能吗?

当然是不可能了,首先内存被划分成若干个和页面大小相等的片。

每个页表项代表一个页面的地址,一般很小。

假设内存大小是2GB,页面大小(物理块)是4KB,页表项长度是4B。

则整个内存可以被划分成2GB/4KB=512K个页面。

页表的长度=页表项的长度x页面的个数=4Bx512K=2M。

内存中用2M的大小来存放页表。

这下清楚了吧,实际上是取了每一个页号对应的页面的起始地址,或许还有对应的物理块号(应该有)。

下面抄写操作系统中的一句话便于理解:

对于一个具有32位逻辑地址空间的分页系统(4GB),规定页面大小为4KB,则在每个进程页表中的页表项

可达1M个之多。4GB/4KB=1M

又因为每个页表项占用1个字节(1B),故每个进程仅仅其页表就要占1MB的内存空间。

而且还要求是连续的,显然这是不现实的,解决问题方法:

1)采用离散分配方式来解决难以找到一块连续的大内存空间的问题。

2)只将当前需要的部分页表项调入内存,其余的页表项仍然驻留在磁盘上,需要时再调入。

快速地址变换机构
上述方法需要访问两次内存,一次是访问页表,确定所存取数据或指令的物理地址,一次是根据该物理地址存取数据或者指令。显然这样的方法较慢。

为此我们可以在地址变换机构中增设一个具有并行查找能力的高速缓冲存储器——快表,又称联想寄存器,用来存放当前访问的若干页表项,加速地址变换过程,命中率达到90%以上

第一步就变为了:将逻辑地址中的页号直接送入高速缓存寄存器,与快表进行匹配,未找到则按慢表处理~

有些处理器设计为快表和慢表同时查找,快表查找成功则终止慢表的查找

两级页表
由于引入了分页管理,进程在执行时不需要将所有页都调入内存页框中,只要将保存有映射关系的页表存入内存中即可,我们这里考虑一下页表的大小,以32位逻辑空间,页面大小4 KB ,页表项大小4 B 为例,若要实现进程对全部逻辑地址空间的映射,则每个进程需要需要2的20次方(2的32次方 / 2的12次方(也就是页面的大小 4 KB ))(表示的也就是页面的个数),约100万个页表项。2的20次方个页表项 * 4 B ,为4 MB ,也就是说每个进程在页表项这一块就需要4 MB 的主存空间,显然这是比较大的内存占用。即使不考虑对全部逻辑地址空间的映射,一个逻辑地址空间稍大的进程,其页表项所占用的主存空间也是过大的。

例:40 MB 的进程,页表项总共占有(40 MB / 4 KB * 4 B ) 40 KB 的主存空间,页面大小为4 KB,那么就需要10 个内存页面来存储整个页表,整个进程需要(40 MB / 4 KB )为1万个页面,在实际执行中只需要几十个页面进入内存框就可以运行, 所以这10个页面的页表相对于实际执行的几十个进程页面来说,内存利用率肯定是比较低的。从另一方面来说,这10个页面的页表也并不需要同时保存在主存中,大多数情况下,映射所需要的页表项都在页表的同一个页面。

综上,为了压缩页表,我们将页表映射的思想进一步延伸,使用一个层次结构的页表——两级页表,从上例中,我们将10页的页表进行地址映射,建立上一级页表,用于存储页表的映射关系。这里对占10个页面的页表进行映射,在上一级页表中只需要10个页表项,所以上一级页表只需要1个页面(4 KB)就足够表示了。在进程的执行过程中,只需要将占用1页的上一级页表存入主存中即可,进程的页表和进程的页面可以后续进行调入。

实际上,我们需要的就是一张索引表,告诉我们第几张页表应该上哪去找,这样就不用将所有的页表存入主存,所以,这就是页表的页表,称为二级页表。规定:为了查询方便,顶级页表最多只能有一个页面。

原文地址:https://www.cnblogs.com/sea520/p/12618742.html