三、存储器抽象:地址空间

要保证多个进程同时处于内存中并且不相互影响,需要解决两个问题:保护和重定位。上一篇中提到的IBM 360采用给内存块标记上保护键,并比较执行进程的键和其访问的内存字的保护键是否相同的方法来进行保护;而对于重定位的实现,IBM 360使用的静态重定位技术是一个缓慢且复杂的方法。

一种更好的办法是创建一个新的内存抽象:地址空间。地址空间是一个进程可用于寻址内存的一套地址集合。每个进程都会有一个自己的地址空间,且个进程间相互独立互不影响(在一些特殊情况下进程可以共享地址空间)。

比较难的是给每个进程分配自己的地址空间,使得不同的进程中相同的逻辑内存对应到不同的物理地址(如进程1中JMP 17与进程2中JMP 17这两个语句跳转到不同的物理地址中)。一种简单的办法是采用基址寄存器和界限寄存器来实现。这个方法曾很常见,但现代CPU可以运行更复杂但更好的机制,现在这个方法已不再使用。

基址寄存器和界限寄存器:

这是一种动态重定位技术,把每个进程的地址空间映射到物理内存的不同部分。从CDC 6600(最早的超级计算机)到Intel 8088都使用这种方法。通过给CPU配置基址寄存器和界限寄存器的方法。基址寄存器用来存储进程的起始物理地址,界限寄存器用来存储进程的长度。每次进行相应的操作,CPU硬件会在把地址发送到内存总线前自动把基址值加到进程发出的地址值上,同时检查是否超过界限。这个方法的缺点是:每次访问内存都要进行加法和比较操作,加法操作在没有使用特殊电路的情况下相对而言会显得比较慢。

上面提到的方法没有考虑计算机物理内存不能同时装载进需要运行的所有进程,而这通常情况下有很大概率会会发生。交换技术和虚拟内存技术都可以用来解决内存超载的问题。这里先介绍交换技术。

交换技术:

交换技术,采用把一个进程完整调入内存,使该进程运行一段时间,然后把他存回磁盘的方法解决内存超载问题。即空闲进程主要存储在磁盘上,不占用内存,在需要再次运行进程的时候在调入内存中。由于一般情况下再次调入内存时进程的物理地址与上一次不再相同,这时动态重定位技术就十分有必要了。

内存在不断的交换过程中会产生多个空闲区,可以通过把所有的进程向下移动把这些小的空闲区组合成一个大的空闲区,称为内存紧缩。但是这个操作需要耗费大量的CPU时间,所以一般不进行。

许多进程的数据段是可增长的,如C++中使用new从堆中动态地分配内存,这时如果进程相邻的不是空闲区,该进程就会出现内存不够用的问题。这时需要将进程移到一个足够大的空闲区去,若没有满足条件的空闲区,进程就会被挂起知道有足够大的空闲区。当大部分进程都需要增长时,可以在进程调入内存时就分配一些额外的空间,避免运行过程中进行交换和移动产生的开销。

空闲区管理:

一般有两种方式跟踪内存的使用情况:位图和空闲链表。

1.       位图

内存被划分成小到几个字或大到几千字节的分配单元。每个分配单元对于位图中的一位,用0/1来表示该分配单元是空闲/占用。分配单元的大小是一个重要的设计因素,分配单元越小则位图越大。如若一个分配单元为4个字节,则没32位的内存就需要位图中的1位来标记,这样位图需要占用1/33的内存空间。但是若太大,当进程所需实际大小不是分配单元整数倍时,最后一个分配单元中就会出现较大的浪费。

位图法的另一个问题是,当需要将占用k个分配单元的进程调入内存时,存储管理器需要搜索位图,在位图中找出k个连续0的串。这一操作是比较耗时的,因为该k个连续0串可能是跨越字的边界的。

2.       链表法

该方法维护一个记录已分配内存段和空闲内存段的链表。链表中的节点包含一个进程所使用内存段,或者包含一个在两个进程间的空闲区的内存段。节点主要包含以下内容:空闲区(H)或进程(P)的指示标记、起始地址、长度、指向下一个节点的指针。

进程表中表示终止进程的节点中通常含有指向对应其段链表节点的指针,进程终止时可以很方便地将所用的内存段改为空闲区。由于需要将相连的空闲区合并起来,故段链表使用双向链表比单链表可能更方便。

当按照地址顺序在链表中存放进程和空闲区时,可以使用以下几种算法来为创建的进程分配内存:

1)       首次适配算法

在该算法中存储管理器沿着段链表进行搜索,直到找到一个足够大的空闲区,除非空闲区大小和要分配的空间大小一样,否则将空闲区分为两部分,一部分供进程使用,另一部分形成新的空闲区。这种算法速度较快。

2)       下次适配算法

类似首次适配算法,但是每次找到合适的位置后都记录当前位置,下次需要分配时从该位置开始搜索而不是从头开始。性能略低于首次适配算法。

3)       最佳适配算法

该算法搜索整个链表,找出能够容纳进程的最小的空闲区。该算法试图找去最接近实际需要的空闲区,最好地匹配请求和可用空闲区,而不是拆分大的空闲区。该算法比首次适配算法慢。且比首次适配算法或下次适配算法浪费更多的内存,因为会产生大量无用的小空闲区。为了避免分裂出很多非常小的空闲区,有一种最差适配算法,该算法总是分配最大的可用空闲区。


可以为进程和空闲区维护各自的段链表,这样上面几种算法分配内存的速度都能得到提升。但是这种做法也会增加复杂度以及使得内存释放速度变慢。进一步地,可以将空闲区链表按大小表虚,这样可以提高最佳适配算法和最差适配算法的速度。

4)       快速适配算法

为那些常用大小的空闲区维护单独的链表。例如:一个n项的表,该表的第一项是指向大小为4KB的空闲区链表表头的指针,第二项是指向大小为8KB的空闲区链表表头的指针,以此类推。该算法寻址一个指定大小的空闲区十分迅速,但是释放内存时将非常费时。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值