【内存管理】之内存空间的分配与回收

目录

连续分配管理方式

单一连续分配

固定分区分配

动态分区分配

动态分区分配算法

首次适应算法(First Fit)

最佳适应算法(Best Fit)

最坏适应算法(Worst Fit)

邻近适应算法(Next Fit)

非连续分配管理方式

基本分页存储管理

基本地址变换机构

具有快表的基本地址变换机构

两级页表

基本分段存储管理

地址变换

分页VS分段

段页式存储管理


操作系统作为资源的管理者,同时也要管理内存,将内存分配给各个进程;当进程运行结束后,回收进程的内存空间。

 

连续分配管理方式

连续分配: 为用户进程必须分配连续的内存空间。

单一连续分配

在单一分配方式中,内存被分为系统区用户区

系统区通常位于内存的低地址部分,用来存放操作系统的相关数据。

用户区用来存放用户程序的相关程序。并且只能存放一道程序,这道程序独占整个系统区。

优点:实现简单;无外部碎片;可以采用覆盖技术扩充内存;不一定需要采取内存保护(eg:早期的 PC 操作 系统 MS-DOS)。

缺点:只能用于单用户、单任务的操作系统中;有内部碎片;存储器利用率极低

 

固定分区分配

20世纪60年代出现了支持多道程序的系统,为了能在内存中装入多道程序,且这些程序之间又不会相互干扰,于是将整个用户空间划分为若干个固定大小的分区,在每个分区中只装入一道作业,这样就形成了最早的、最简单的一种可运行多道程序的内存管理方式。

分区方式有俩种:分区大小相等分区大小不等

 

分区大小相等:缺乏灵活性,但是很适合用于用一台计算机控制多个相同对象的场合(同一个程序启动的不同进程,比如在电脑上登录多个QQ)

分区大小不等:增加了灵活性,可以满足不同大小的进程需求。根据常在系统中运行的作业大小情况进行划分。

分区说明表

操作系统需要建立一个数据结构——分区说明表,来实现各个分区的分配与回收。每个表项对应一个分区,通常按分区大小排列。每个表项包括对应分区的大小、起始地址、状态(是否已分配)。

当某用户程序要装入内存时,由操作系统内核程序根据用户程序大小检索该表,从中找到一个能满足大小的、未分配的分区,将之分配给该程序,然后修改状态为“已分配”。

优点:实现简单,无外部碎片。

缺点:a. 当用户程序太大时,可能所有的分区都不能满足需求,此时不得不采用覆盖技术来解决,但这又会降低 性能;

b. 会产生内部碎片,内存利用率低。

动态分区分配

动态分区分配又称为可变分区分配。这种分配方式不会预先划分内存分区,而是在进程装入内存时,根据进程的大小动态地建立分区,并使分区的大小正好适合进程的需要。因此系统分区的大小和数目是可变的。

空闲分区表与空闲分区链:用于系统记录内存的使用情况。

空闲分区表:每个空闲分区对应一个表项。表项中包含分区号、 分区大小、分区起始地址等信息。

 

空闲分区链:每个分区起始部分和末尾部分各设置一个指针分别指向前一个空闲分区和后一个空闲分区,每个分区节点还记录着分区编号和分区大小等信息。

 

思考1:当很多个空闲分区都能满足需求时,应该选择哪个分区进行分配?

把一个作业装入内存时,需要按照一定的动态分配算法从空闲分区表或者空闲分区链中选取一个分区来存储作业的相关数据。

思考2: 如何进行分区的分配与回收操作? 假设系统采用的数据结构是“空闲分区表”... 如何分配?

回收进程后,相对应的分区如果有空闲分区则合并。

思考3:如果新增一个表项,该如何编号?

编号不一定按照地址大小排列或者分区空间大小排列,而是需要根据动态分配算法来确定。

PS:动态分区分配在装入时,应该采取动态运行时装入方式

因为动态运行是装入方式是在进程运行时才计算其中的物理地址,而计算物理地址需要进程的起始地址,而动态分区分陪比较灵活,在装入的时候才会为作业分配内存分区,才能确定进程的起始地址;而且使用动态运行时装入方式也更灵活。俩种方式都比较灵活又不冲突,支持进程的内存变换。

动态分区分配算法

在动态分区分配方式中,如果很多个空闲分区都满足进程的大小,那么给进程分配哪个分区呢?

首次适应算法(First Fit)

算法思想:每次都从低地址开始查找,找到第一个能满足大小的空闲分区。

如何实现:空闲分区以地址递增的次序排列。每次分配内存时顺序查找空闲分区链(或空闲分区表),找到大小能满足要求的第一个空闲分区。

最佳适应算法(Best Fit)

算法思想:由于动态分区分配是一种连续分配方式,为各进程分配的空间必须是连续的一整片区域。因此为了保证当“大进程”到来时能有连续的大片空间,可以尽可能多地留下大片的空闲区,即,优先使用更小的空闲区。

如何实现:空闲分区按容量递增次序链接。每次分配内存时顺序查找空闲分区链(或空闲分区表),找到大小能满足要求的第一个空闲分区。

缺点

会产生大量的内存碎片。

每次优先使用最小的内存分区,那么就会留下越来越多的更小的、难以利用的碎片。

算法开销大。

每次分配内存后都需要重新对内存分区排序,来保证空闲分区表或者空闲分区链是按容量依次递增排序的。

最坏适应算法(Worst Fit)

算法思想:为了解决最佳适应算法的问题——即留下太多难以利用的小碎片,可以在每次分配时优先使用最大的连续空闲区,这样分配后剩余的空闲区就不会太小,更方便使用。

如何实现:空闲分区按容量递减次序链接。每次分配内存时顺序查找空闲分区链(或空闲分区表),找到大小能满足要求的第一个空闲分区。

缺点

优先使用大的内存分区,当占用内存很大的进程到来时,可能就没有内存分区满足了。

这种时候可以使用覆盖技术完成进程的正常运行,但是也会增大开销,降低系统性能。

系统开销大。同佳适应算法。

邻近适应算法(Next Fit)

算法思想:首次适应算法每次都从链头开始查找的。这可能会导致低地址部分出现很多小的空闲分区,而每次分配查找时,都要经过这些分区,因此也增加了查找的开销。如果每次都从上次查找结束的位置开始检索,就能解决上述问题。

如何实现:空闲分区以地址递增的顺序排列(可排成一个循环链表)。每次分配内存时从上次查找结束的位置开始查找空闲分区链(或空闲分区表),找到大小能满足要求的第一个空闲分区。

首次适应算法每次都从低地址开始查找第一个能够满足进程的内存分区,这就决定了当低地址区域中即使有更小的内存分区,只要能够满足某个进程就会被分配,增大了内存碎片被使用的可能。同时,也更有可能留下高地址区域的大容量内存分区能够留下来。(最佳适应算法的优点)

邻近适应算法中,无论高地址还是低地址中的大容量分区都有相同的概率被使用,从而划分为更小的分区。不能满足后续大进程的要求。(最坏适应算法的缺点)

最佳适应算法和最坏适应算法的开销较大,首次适应算法和邻近适应算法的开销较小;而首次适应算法更优于邻近适应算法,因此四种算法中,首次适应算法的效果反而最好。

非连续分配管理方式

非连续分配: 为用户进程必须分配离散的内存空间。

基本分页存储管理

分页存储:将内存空间分成若干个大小相等的分区(每个“页框”大小一般为4KB),每个分区为一个“页框”,每个页框的编号称为“页框号”,页框号从0开始。将进程的逻辑地址空间也分为一个个同页框大小相等的页面(或者称为页),每个页面的编号称为“页号”,页号也是从0开始的。

操作系统以页框为单位为进程分配内存空间,进程的每个页面都放入一个页框中。即页框和页面是一一对应的。

进程的页面在内存中不一定是连续的,可以使离散的。(非连续分配方式)

进程的最后一页有可能小于页框的大小,因此会产生内部碎片。

因此,页框的分配不宜过大,这样可以减少内部碎片的产生。

页框还有几个别称:页帧、内存块、物理块、物理页面。

页框号也有相对应的别名。

页表:页框与页面是一一对应的,这种对应关系用页表来存储。

用来记录进程的每个页面都存放在哪个页框中。

因为页表是用来记录进程的页面与内存的页框,所以页表存放在进程的PCB中,方便进程对页面的管理。

页表的特点:

  • 一个进程对应一张页表。

  • 进程的每个页面都对应一个内存的页框。

  • 每个页表项都是由“页号”和“页框号”组成。(构成一一对应关系)

  • 页表记录进程页面与实际存放的内存块一一对应的关系。

  • 每个页表项的长度都是向相等的。

问题一:每个页表项占多少个字节?

 

页表由页号和内存号组成,并且页号是从0开始的;可以把页表比作数组,页号相当于数组的下标,那么页号的表示可以和数组下标一样隐含表示,也就是说从逻辑上从0开始依次递增,但是不用占用内存空间来记录。那么每个页表项的大小也就是内存块的大小。

问题二:如何实现逻辑地址到物理地址的转换?

特点:虽然进程的各个页面是离散存放的,但是页面内部是连续存放的 。

如果要访问逻辑地址 A,则

①确定逻辑地址A 对应的“页号”P

②找到P号页面在内存中的起始地址(需要查页表)

③确定逻辑地址A 的“页内偏移量”W

逻辑地址A 对应的物理地址 = P号页面在内存中的起始地址+页内偏移量W

子问题:如何确定一个逻辑地址对应的页号、页内偏移量?

 

页号 = 逻辑地址 / 页面长度 (取除法的整数部分)

页内偏移量 = 逻辑地址 % 页面长度(取除法的余数部分)

基本地址变换机构

基本地址变换机构可以根据进程的页表将逻辑地址变为物理地址。方法是在系统中设置一个页表寄存器,存放页表的起始地址F和页表长度M。进程未执行时,页表的起始地址和页表长度是存放在PCB中,当进程被调度时,操作系统会把它们放到页表寄存器中。

 

在分页存储管理(页式管理)的系统中,只要确定了每个页面的大小,逻辑地址结构就可以确定了。因此,页式管理中地址是一维的,即只需要告诉操作系统逻辑地址即可,操作系统会根据逻辑地址和页面大小算出页号和页内偏移量。

具有快表的基本地址变换机构

是基本地址变换机构的改进版本,通过快表来加快了地址转换速度。

快表:又称联想寄存器(TLB, translation lookaside buffer ),是一种访问速度比内存快很多的高速缓存(TLB不是内存!),用来存放最近访问的页表项的副本,可以加速地址变换的速度。与此对应,内存中的页表常称为慢表

 

 

①CPU给出逻辑地址,由某个硬件算得页号、页内偏移量,将页号与快表中的所有页号进行比较。

② 如果找到匹配的页号,说明要访问的页表项在快表中有副本,则直接从中取出该页对应的内存块号,再将 内存块号与页内偏移量拼接形成物理地址,最后,访问该物理地址对应的内存单元。因此,若快表命中,则 访问某个逻辑地址仅需一次访存即可。

③如果没有找到匹配的页号,则需要访问内存中的页表,找到对应页表项,得到页面存放的内存块号,再将内存块号与页内偏移量拼接形成物理地址,最后,访问该物理地址对应的内存单元。因此,若快表未命中,则访问某个逻辑地址需要两次访存(注意:在找到页表项后,应同时将其存入快表,以便后面可能的再次访问。但若快表已满,则必须按照一定的算法对旧的页表项进行替换)。

局部性原理

增加了快表之后为什么地址变换更快了?

时间局部性:如果执行了程序中的某条指令,那么不久后这条指令很有可能再次执行;如果某个数据被访问过,不久之后该数据很可能再次被访问。(因为程序中存在大量的循环)

空间局部性:一旦程序访问了某个存储单元,在不久之后,其附近的存储单元也很有可能被访问。(因为很多数据在内存中都是连续存放的)

地址变换过程访问一个逻辑地址的访存次数
基本地址变换机构①算页号、页内偏移量 ②检查页号合法性 ③查页表,找到页面存放的内存块号 ④根据内存块号与页内偏移量得到物理地址 ⑤访问目标内存单元两次访存
具有快表的地址变换机构①算页号、页内偏移量 ②检查页号合法性 ③查快表。若命中,即可知道页面存放的内存块号,可直接进行⑤; 若未命中则进行④; ④查页表,找到页面存放的内存块号,并且将页表项复制到快表中 ⑤根据内存块号与页内偏移量得到物理地址 ⑥访问目标内存单元快表命中,只需一次访存 快表未命中,需要两次访存
两级页表

单机页表的问题

问题1:页表必须连续存放,因此当页表很大时,需要占用很多个连续的页框。

解决:把页表再分页并离散存储,然后再建立一张页表记录页表各个部分的存放位置,称为页目录表,或称外层页表,或称顶层页表。形成二级页表。

两级页表的地址结构

 

 

实现地址变换

 

问题2:没有必要让整个页表常驻内存,因为进程在一段时间内可能只需要访问某几个特定的页面。

解决:可以在需要访问页面时,再将页面调入内存中(虚拟存储技术)。在页表中增加一个标志位,用来记录改页是否在内存中。

 

多级页面(n级)访问内存的次数 = n + 1。

基本分段存储管理

进程的地址空间:按照程序自身的逻辑关系划分为若干个,每个段都有一个段名(在低级语言中,程序员使用段名来编程),每段从0开始编址 。

内存分配规则:以为单位进行分配,每个段在内存中占据连续空间,但各段之间可以不相邻。

分段系统的逻辑地址结构由段号(段名)和段内地址(段内偏移量)所组成。

段表:程序分多个段,各段离散地装入内存,为了保证程序能正常运行,就必须能从物理内存中找到各个逻辑段的存放位置。为此,需为每个进程建立一张段映射表,简称“段表”。

  1. 每个段对应一个段表项,其中记录了该段在内存中的起始位置(又称 “基址”)和段的长度。

  2. 各个段表项的长度是相同的。

地址变换

 

分段相比较于分页,最大且最本质的区别就是每个页的大小都是相等的,而段的大小是根据程序的逻辑划分的,是不相等的。因此,段表中还要记录段长。并且在分段管理的地址变换中,还要进一步比较段内地址和段长的大小,看是否合法。

分页VS分段
  1. 页是信息的物理单位。分页的主要目的是为了实现离散分配,提高内存利用率。分页仅仅是系统管理上的需要,完全是系统行为,对用户是不可见的。

    段是信息的逻辑单位。分段的主要目的是更好地满足用户需求。一个段通常包含着一组属于一个逻辑模块的信息。分段对用户是可见的,用户编程时需要显式地给出段名。

  2. 页的大小固定且由系统决定。段的长度却不固定,决定于用户编写的程序

  3. 分页的用户进程地址空间是一维的,程序员只需给出一个记忆符即可表示一个地址。

    分段的用户进程地址空间是二维的,程序员在标识一个地址时,既要给出段名,也要给出段内地址。

  4. 分段比分页更容易实现信息的共享和保护。 不能被修改的代码称为纯代码或可重入代码(不属于临界资源),这样的代码是可以共享的。可修改的代码是不能共享的(比如,有一个代码段中有很多变量,各进程并发地同时访问可能造成数据不一致)。

     

段页式存储管理

分页、分段优缺点分析

优点缺点
分页管理内存利用率高,不会产生外部碎片,只会产生少量的内部碎片不方便按逻辑模块实现信息的共享和保护
分段管理很方便按逻辑模块实现信息的共享和保护如果段长过大,为其分配很大的内存空间很不方便.另外,还会产生外部碎片

分段+分页 = 段页式管理

段页式系统的逻辑地址结构由段号、页号、页内偏移构成。

分段对用户是可见的,在编程时需要给出段号和段内地址。而将各段再分页对用户来说是不可见的,系统会根据段内地址自动划分页号和页内偏移量。因此,段页式管理的地址是二维的。

段表与页表

 

地址转换

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值