前言
前面讲了内存的分段,这才是内存管理的起点。接下来,分段和分页结合使用才能真正的管理和使用内存
提示:以下是本篇文章正文内容
一、内存分区
分区式存储管理是把内存分为一些大小相等或不等的分区,操作系统占用其中一个分区,其余的分区由应用程序使用,每个应用程序占用一个或几个分区。分区式存储管理虽然可以支持并发,但难以进行内存分区的共享。
专业术语介绍
(1)内碎片与外碎片:
内碎片是占用分区内未被利用的空间,外碎片是占用分区之间难以利用的空闲分区(通常是小空闲分区)。
(2)内存紧缩:将空间分区合并需要移动一个段(复制内容),消耗大量时间,影响操作系统性能
1.固定分区
固定分区:把内存划分为若干个固定大小的连续分区,这种作法只适合于多个相同程序的并发执行(处理多个类型相同的对象)。分区大小也可以不等:有多个小分区、适量的中等分区以及少量的大分区。根据程序的大小,分配当前空闲的、适当大小的分区。
优点:易于实现,开销小
缺点:内碎片造成浪费;分区总数固定,限制了并发执行的程序数目
2.动态分区
动态分区就是动态创建分区,在装入程序时按其初始要求分配,或在其执行过程中通过系统调用进行分配或改变分区大小。
动态分区的分区分配就是寻找某个空闲分区,其大小需大于或等于程序的要求。若是大于需求,则将该分区分割成两个分区,其中一个分区为要求的大小并标记为“占用”,而另一个分区为余下部分并标记为“空闲”。
分区分配的先后次序通常是从内存低端到高端。动态分区的分区释放过程中有一个要注意的问题是,将相邻的空闲分区合并成一个大的空闲分区。
与固定分区相比较:没有内碎片,但它却引入了另一种碎片——外碎片。
(1)可变分区的管理过程——核心数据结构
通过已分配分区表和空闲分区表两张表来记录分区使用情况。当有段请求时,空闲分区表将改变
(2)可变分区的管理—请求分配
在上图中,原本内存中已分配了seg1和seg2,空闲分区从地址250k开始,大小为250K,现有一个100k大小的段请求,于是250k-350k被分配给了新请求段seg3,空闲分区还剩下150k
(3)可变分区的管理—释放内存
同时由于进程可能被换入换出,所以内存中已分配的空间有可能被释放,因此空闲分区可能存在多段
(4)可变分区的管理—再次申请
当存在多个空间分区时,再来一个段提出内存请求,该选谁?所以引入了三个分区分配算法
3.分区分配算法
(1)最先适配法(nrst-fit)
按分区在内存的先后次序从头查找,找到符合要求的第一个分区进行分配。该算法的分配和释放的时间性能较好,较大的空闲分区可以被保留在内存高端。但随着低端分区不断划分会产生较多小分区,每次分配时查找时间开销便会增大。
(2)最佳适配法(best-fit)
按分区在内存的先后次序从头查找,**找到其大小与要求相差最小的空闲分区进行分配。**从个别来看,外碎片较小;但从整体来看,会形成较多外碎片优点是较大的空闲分区可以被保留。
(3)最坏适配法(worst- fit)
按分区在内存的先后次序从头查找,找到最大的空闲分区进行分配。基本不留下小空闲分区,不易形成外碎片。但由于较大的空闲分区不被保留,当对内存需求较大的进程需要运行时,其要求不易被满足。
首先适配快,但其他分区就浪费时间,最佳分配需要遍历内存
因此需要引入分页:解决内存分区导致的内存效率问题
二、内存分页
1.引入分页
引入分页: 解决内存分区导致的内存效率问题
可变分区多次分配以后就会形成内存碎片,当再来一个段请求大于每个单个空间空间时,就需要将内存合并:内存紧缩,内存紧缩需要花费大量时间
解决方法:将每个段分成多页,内存也分成很多页,页是最小分配单位,这样每次分配段空间,最多浪费不超过一页,没有内存碎片
其实也有会部分内存没有使用到,但是注意这种思想,页是一个单位,每次分配的内存都是整数个页,也就是将这些分配出去的页都看成是已经使用的了,所以就没有内存碎片。==所以从内存角度来说这种方式是比较好的,也就是物理内存想要分页,但是用户程序希望是分段。==后面会说到的
每个段在计算物理地址时需要查找段的基址,那么将段分成页后,计算物理地址需要查找页的基址,物理地址=页基址+逻辑地址。
PCB中存在页表保存每个段的页分配信息,为了取分段的页,将内存的页叫作页框
内存分段的有一个段表,分页自然也要有一个页表。有一个专门的寄存器存储页表的地址。
注意页在内存的排布顺序并不是按照地址的顺序递增的,也就是说页0不一定是放在地址零处,这里引入页框,页框是按照内存顺序排列的,并且页框的大小和页是相同的
分析mov [0x2240],%eax
图片中: mov [0x2240],%eax
2240地址表示的实际内存地址是多少?首先看它是那一页的,每一页的大小为
4k,0x2240除以4K得到页号,除以4K也就是右移12位,得到2,即第二页,根据页
号找到具体的页框号,在上图中为3,具体的地址就是3*4K+240=3240,即物理地
址为3240.
2.多级页表
为了提高内存的利用率,内存是分页管理的,并且有一个页表用来存储页号与页框的对应关系。
但是,为了更好的提高内存的利用率,每一页就应该做得足够小,但是每一页都要在页表里面有一项与页框对应,也就是说页数越多页表也就会越大,页表如果很大的话就会对内存造成浪费,因为存放页表的这部分你内存是不能给程序使用的,并且一直存放在该进程的PCB里面
(1)只存放用到的页
只用到0,1,3就存放这三页,如图
若这存放用到的页,但这样的话页表的项就不连续了,找某一页对应的页框就不能直接使用偏移量的形式,较高查找效率是折半查找(因为页号是有顺序的),即便使用折半查找耗费的时间也会比使用偏移量大很多倍。
所以页表的页号必须是连续的。
(2)多级页表(页目录表+页表)
页目录表的每一项对应一个页表,然后再根据页表找到对应的页。
一个逻辑地址用10bits的页目录号+10bits的页号+12bits的偏移组成
这种思想就类似于书本的目录,目录的地方有一个章目录(页目录表)和节目录(页表),如果要查找某一节的内容首先找到这一章的地方,然后再查具体的某一节
不仅能节省大量内存,并且保证了章目录和节目录都是连续的,所以可以使用偏移量的形式查找对应的章节
3.快表TLB
多级页表提高了空间效率,但是在时间的效率上非常低。因为每一次访问的时候都要根据章目录找到页目录再找到具体的页。也就是需要访问三次内存,cpu每一条指令执行的时间其实大部分都是浪费在访问内存上
解决方法:在CPU与内存访问之间加一组TLB,TLB是一组寄存器,用来存放最近使用过的页对应的页框号
这样如果CPU需要访问某一页首先在TLB里面找,如果TLB里面有就不用访问内存了,因为TLB是寄存器,cpu访问寄存器的速度远大于对内存的访问速度,大大地提升时间性能了。
提升时间性能最主要的因素就是可以在TLB里面直接找到该页对应的页框号。
要提升命中率,TLB肯定是越大越好,但是TLB材料很贵,不会做得很大。TLB的大小大概是[64,1024]。
为什么TLB里面存放这么少的项就能实现“近似访存1次”?
因为程序的局部性原理,程序的局部性原理在用户程序里面多对应的是循环,顺序结构
总结
提示:这里对文章进行总结:
为了提高内存的空间性能,提出了多级页表;但是提到空间性能是以浪费时间性能为基础的,因此为了补充损失的时间性能,提出了快表(即TLB),快表利用的是程序的局部性原理。