现代操作系统——地址空间、交换技术、虚拟内存

地址空间

进程可用的内存空间。


多道程序设计引发的两个问题——保护和重定位。

保护:由于多个进程共用一个内存,如何保证进程不修改其它进程地址空间的内容?

重定位:由于多个进程共用一个内存,设有两个进程A、B均在内存中,两者均有一条指令访问地址28的内容,如何保证两个进程访问各自的地址空间?

解决方法:保护——限定进程可以访问的地址空间的范围,重定位——不使用绝对地址,使用相对地址。

上述解决方案的实现就是基质寄存器和界限寄存器,每当一个进程分配到地址空间时,地址空间的下限地址被加载到基址寄存器,上限地址加载到界限寄存器,每当进程进行内存访问时,内存地址=基质寄存器值+进程发出的地址值,内存地址要与界限寄存器值进行比较,若大于,则发生错误,基址寄存器和界限寄存器的值只有操作系统可以更改。


交换技术与虚拟内存

问题:所有进程所需要的内存大小大于物理内存大小。

解决思路

交换技术:把一个进程调入内存空间运行,运行一段时间后写入硬盘,腾出空间给其他进程运行,再次运行时在读入内存。

虚拟内存:将程序所需要的内存进行分块(称为页面),每次只有一部分分块(页面)在内存中,若访问的分块(页面)不在内存中,指令执行失败,引起缺页中断,CPU进入内核态,从硬盘中加载缺失分块,根据某些算法选择某块分块进行替换,重新执行失败的指令。


交换技术相关概念

内存压缩:由于进程交换,可能会产生内存碎片,此时会将所有的进程尽可能的往下移动,此操作耗时较长,一般不会这么做。


空间内存管理

两种数据结构存储空闲内存——位图、链表。


位图:把内存按固定大小块(称为分配单元)进行划分,每个分配单元对应位图中的一位,1代表被占用,0代表没有。

位图的缺点:由于进程占用的内存空间可能不是分配单元的整数倍,所以可能会导致一些空间的浪费。

位图寻找空闲内存的方式:假设进程A需要k个分配单元,则在位图中查找连续k个0的串,这将是一个耗时的操作(由于位图中该串可能跨越字的边界)


链表:维护一个记录已分配内存段和空闲内存段的链表,量表的每个节点包括:空闲与否的标志、起始地址、长度、指向下一节点的指针,当进程释放内存后,操作系统将会查找相邻块,以确定是否可以合并,从而减少内存碎片的产生。

链表寻找空闲内存的方式:

1、首次适配算法:存储管理器沿着链表进行搜索,直到找到第一个足够大的空闲区。将该空闲区进行划分,一部分给进程使用,另一部分形成新的空闲区。

2、下次适配算法:与首次适配算法类似,不同点在于每次找到合适的空闲区时都做一个记录,下次为该进程分配空间时便从此处开始搜索,该算法性能略低于首次适配算法

3、最佳适配算法:搜索整个链表,找到能容纳进程的最小空闲区,算法效率低下

4、最差适配算法:搜索整个两边,找到能容纳进程的最大空闲区,算法效率低下

改善上述算法的策略:

分别为空闲区和进程维护一个链表(减少链表长度),空闲区链表可以按照空闲区的大小进行排序,从而提高最佳适配算法的效率

5、快速适配算法:为常用大小的空闲区维护单独的链表,例如:链表的第一项指向大小为4KB(不止一个)的空闲区链表表头,第二项指向大小为8KB的空闲区链表表头........


位图与链表的比较(个人理解):

位图的结构决定了位图不需要链表中的空闲区合并操作,链表的灵活性决定了链表比位图的查找效率更高(可以将空闲内存单独取出来构成链表,减少了搜索长度)


交换技术应注意的问题

由于进程所真正使用的内存空间可能是变换的,例如数据段的增长,所以一般会给进程分配多一点内存,在进程写回硬盘时,分配内存中的空闲内存不需要写回硬盘。


虚拟内存的基本概念

虚拟地址:应用程序产生的地址,由MMU将其映射到物理地址上

页框:物理内存也会进行相应的分块,每一块就称为是页框,页框大小与页面大小一致

页表:记录页面状况的表格,每一项称为是一条页表项,假设应用程序有N条页面,则有N个页表项,每条页表项的结构根据机器的不同而不同,但内容大致相似,内容如下:

    1、在/不在位:表明页面是否映射到物理内存

    2、保护位:指明该页面支持什么操作——读、写、执行,起到保护页面的作用

    3、修改位:指明该页面是否被修改过,若页面被修改过,那么在置换该页面时,将会将该页面的内容写回到硬盘中

    4、访问位:指明该页面是否被访问过,设置修改位也会导致访问位被设置,有些页面置换算法会依据此位置换最近没有被访问过的页面

    5、指明该页面是否能映射到内存:有些页面应该映射到设备寄存器而不是内存,有时候程序需要直接从设备寄存器中读取信息而不是从内存中读取设备的拷贝消息

    6、页框号:指明该虚拟页面对应的物理内存中的哪个页框(前提:页面有映射到页框号)

    7、每个页面对应的硬盘地址不在页表中,这部分信息由操作系统保存

    页表的工作方式:虚拟地址由虚拟页号和偏移量组成,虚拟页号可以作为页表的索引,用于查找对应的页表项,若该页面在内存中,则将虚拟地址中的虚拟页号替换成页框号即为物理地址,否则,引发缺页中断,通过页面置换算法选择页面进行替换,重新执行之前失败的指令。


虚拟内存的问题和解决方案

虚拟地址到物理地址的映射速度必须非常快,页表大小与应用程序的页面个数一致,若应用程序有100万个页面,则页表也将会有100万个页表项,进行检索将会是一个非常缓慢的过程。

解决方案:在数据结构中有一个分类的思想,即将大规模的数据进行分类,这样每次查询时只要查询相应类别中的数据即可,即将大规模的数据划分为小规模的数据,虚拟内存也运用了这种策略,程序运行时只会频繁访问某些页面,将这些页面抽取出来,用一个单独的缓冲区进行维护,每次映射时,先查找该缓冲区,若缓冲区查找不到,在到页表中查找,同时置换缓冲区中的某个页面,由于缓冲区中的页表项比页表要小很多,因此映射速度大大提高,这个缓冲区被称为TLB,TLB中的每个表项包括虚拟页号、有效号(指明该表项是否有效)、保护位、页框号、修改位,当从TLB中清除表项时,相应的修改位会被写入页表中对应的页表项


虚拟地址很大的话,将会导致页表非常大,例如——4GB的虚拟地址,若每个页面占用4MB,则需要100万个页面,会耗费一定量的内存

解决方法:采用多级页表结构,整个结构和树很像,拿上述的例子来说,4GB对应32位二进制,选择前10位为第一级页表的索引,中十位为第二级页表的索引,剩余12位为偏移量,从而构成多级页表,但从内存来看,似乎多级页表占用了更多内存,共需要1024*1024个页表项(多级页表中的页表项的结构和单集页表中的页表项相似),同时还需要内存来存储指针(用于一击页表指向二级页表),其实多级页表采用了一种需时加载的策略,即当进程访问的页面不存在页表时,才会创建对应的页表,且一般情况下,进程需要访问的页表一般是固定的,所以就会导致多级页表占用的内存比单级页表要小,为什么多级页表要采用树状结构呢,不采用线性结构?因为树状结构的搜索新能比线性结构要好,使用线性结构(用链表),每次查找都必须从头开始查找,而树状结构利用了分类的思想,减少了每个节点的页表项的个数,从而加快了搜索速度。


虚拟内存的其余概念

软失效:访问的页表在内存不在TLB产生的失效。

硬失效:访问的页面不在内存和TLB中时产生的失效。

次要缺页错误:访问的页面在内存中,但没有记录在进程的页表中。

严重缺页错误:访问的页面不在内存中。



猜你喜欢

转载自blog.csdn.net/dhaiuda/article/details/79989547
今日推荐