分层存储器体系
在现代计算机中,存储器是信息处理的来源与归宿,占据重要位置。但是,在现有技术条件下,任何一种存储设置,都无法同时从速度与容量两方面满足用户的需求。实际上它们组成了一个速度由快到慢,容量由小到大的存储装置层次。由操作系统协调这些存储器的使用。
内存管理的功能
- 主存的分配和管理:当用户需要内存时,系统为之分配相应的存储空间;不需要时及时回收以供其他用户使用。
- 提高主存储器的利用率:不仅能使多道程序动态地共享主存,提高主存利用率,最好还能共享主存中某个区域的信息。
- “扩充”主存容量:为用户提供比主存物理空间大得多的地址空间,以使用户感觉他的作业是在这样一个大的存储器中运行
- 存储保护:确保多道程序都在各自分配到存储区域内操作,互不感染,防止一道程序破坏其他作业或系统文件的信息。
地址空间与存储空间
地址空间是一个进程可用于寻址内存的一套地址集合。每个进程都有一个自己的地址空间,并且这个地址空间独立于其他进程的地址空间。
存储空间是主存中物理单元的集合。
逻辑地址(相对地址,虚地址):用户的程序经过汇编或编译后形成目标代码,目标代码通常采用相对地址的形式,其首地址为 0,其余指令中的地址都相对于首地址编址。不能用逻辑地址在内存中读取信息。
物理地址(绝地地址,实地址):内存中存储单元的地址,可直接寻址。
内存共享
两个或多个进程共用内存中相同区域。
目的:节省内存空间,提高内存利用率;实现进程通信(数据共享)
共享内容:代码共享,数据共享
内存保护与安全
为多个程序共享内存提供保障,使在内存中的各道程序,只能访问它自己的区域,避免各道程序间相互干扰,特别是当一道程序发生错误时,不致于影响其他程序的运行。通常由硬件完成保护功能,由软件辅助实现。
- 保护系统程序区不被用户侵犯
- 不允许用户程序读写不属于自己地址空间的数据(系统区地址空间,其他用户程序的地址空间)
保护过程:防止地址越界。每个进程都有自己独立的进程空间,如果一个进程在运行时所产生的地址在其地址空间之外,则发生地址越界。即当程序要访问某个内存单元时,由硬件检查是否允许,如果允许则执行,否则产生地址越界中断,由操作系统进行相应处理。
地址映射
处理器在执行指令时,必须把逻辑地址转换为物理地址后,才能存取信息。
- 程序地址就是物理地址:程序在编写或编译时进行地址映射。无地址空间概念。
- 问题:两个程序都引用了绝对物理地址。
- 静态地址映射:程序在装载时进行地址映射。
- 缺点:一个已开始执行的程序是无法在主存中移动的,如果该程序因某种原因暂时存放到辅存,若再调入主存时必须把它放回到主存的同一位置。
- 动态地址映射:程序在运行时进行地址映射。CPU 配置两个特殊硬件寄存器,基址寄存器和界限寄存器。程序装载到内存中连续的空闲位置且装载期间无需重定位,当一个程序运行时,程序的起始物理地址装载到基址寄存器中,程序的长度装载到界限寄存器中。
连续分配内存管理
连续分配为一个程序分配一个连续的内存空间。分为:
- 单一连续分配方式
- 分区分配/存储方式(可用于多道程序)
单一连续分配方式
在单道环境下,不管是单用户系统还是单道批处理系统,进程(作业)执行时除了系统占用一部分主存外,剩下的主存区域全部归它占用。
主存划分为:系统区、用户区。系统区功操作系统使用,用户区供用户使用。用户区是一个连续的存储区所以又称单用户存储管理。
特点:单用户系统在一段时间内,只有一个进程在内存,所以内存分配管理十分简单,但内存利用率低。
分区存储
将内存区域中划分为多个区,给每个作业分配一个区使用,并且每个作业只能在被分配的区中运行。
固定分区
在处理作业之前存储器就已经被划分为若干个分区,每个分区的大小可以相同,也可以不同。但是一旦划分好分区后,主存储器中的分区的个数就固定了,且每个分区的大小固定不变。
- 缺点:由于每个作业不一定恰好等于分区大小,所以会产生大量的内碎片,造成内存空间浪费。
可变分区
在作业加载时由操作系统根据作业实际大小来分配分区(作业大小等于分区大小)。这种方式能解决固定分区内存浪费的问题。
有两种方法跟中内存使用情况:位图和空闲区链表。
位图
内存中可能被划分成小到几个字达到几千字节的分配单元。每个分配单元对应位图中的一位,0 表示空闲,1 表示占用。
- 缺点:查找位图中指定长度的连续 0 串是耗时的,因为位图中该串可能跨越字的边界。
空闲区链表
维护一个记录已分配内存段和空闲内存段的链表。其中链表中的一个结点或者包含一个进程或者是两个进程间的一块空闲区。
- 进程终止或换出时链表的更新非常直接。
内存分配
分区的分配算法使用的数据结构是空闲区链表,按空闲区链表的方式不同,可以有以下四种算法:
- 最佳适应法:接到内存申请时,在空闲区链表中找到一个不小于请求的最小空块进行分配为作业选择分区时总是寻找其大小最接近于作业所要求的存储区域。要求将空闲区按大小顺序形成空闲区链表。
- 特点:用最小空间满足要求,保留大的空闲区。
- 是否最优?当次最优,但宏观上未必最优,因为每次分配后所分割下的剩余部分,总是最小的,很难再利用,从而形成碎块。
- 最坏适应法:接到内存申请时,在空闲区链表中找到一个不小于请求的最大空块进行分配,与最佳适应法相反,它在作业选择存储块时,总是寻找最大的空白区。
- 特点:尽量利用存储空间,节约时间和开销,当分割后空闲块仍为较大空块,但是空间浪费比较大,碎片多。
- 首次适应法:要求空闲区链表以地址递增的次序链接。分配内存时,从链首开始顺序查找,直到找到满足其大小要求的空闲为止。
- 特点:该算法倾向于优先利用内存低址区,从而保留高址部分的大空闲区,但会在低址区留下很多碎片,而每次查找又都是从低址区开始,无疑会增加查找空闲分区的开销。
- 下次适应法(循环首次适应法):类似首次适应法每次分区时,总是从上次查找结束的地方开始,找到一个足够大的空白区分配。
- 减少查找空闲分区开销,使内存中空闲分区分布更均匀,但会缺乏大的空闲分区。
内存回收
碎片问题与拼接技术
碎片问题:经过一段时间的分配回收后,内存中存在很多很小的空闲块。它们每一个都很小,这些空闲块被称为碎片。
解决:拼接技术,通过内存移动程序将所有小的空闲区域合并为大的空闲区域。
- 拼接时机的选择:
- 在某个分区回收时立即进行拼接
- 当找不到足够大的空闲区,而空闲区的存储容量总和却可以满足作业需要时进行拼接。
内存超载
所有进程需要的内存数量总和通常要远远超出存储器能够支持的范围。
用户在编制程序时,不应受内存容量限制,所以要采用一定技术来“扩充”内存容量,使用户得到比实际内存容量大得多的内存空间。
具体实现:在硬件支持下,软硬件相互协作,将内存和外存结合起来统一使用。扩充内存使用户编制程序时不受内存限制。
处理内存超载的方法
交换技术
把一个进程完整调入内存,使该进程运行一段时间,然后把它存回磁盘,下次运行时再重新调入。
- 缺点:磁盘的存取速度慢,导致需要长时间才能换出一个大容量程序。
覆盖技术
把程序划分为若干个功能上相互独立的程序段,按照其自身的逻辑结构将那些不会同时执行的程序段共享同一块内存区域。程序段先保存在磁盘上,当有关程序的前一部分执行结束,把后续程序段调入内存,或者占用前面的程序段的上方位置(如果有空间),或者占用前面的程序段(如果没有空间)。一般要求作业各模块之间有明确的调用结构,程序员要向系统指明覆盖结构,然后由操作系统完成自动覆盖。
- 缺点:将一个大程序分割成小的、模块化的片段是非常费时和枯燥的,并且易出错。
虚拟内存
虚拟内存是计算机系统内存管理的一种技术,它使得应用程序认为它拥有连续的可用的内存(一个连续完整的地址空间),而实际上它通常是被分隔成多个物理内存碎片,还有部分暂时存储在外部磁盘存储器上,在需要时进行数据交换。
每个程序拥有自己的地址空间,这个空间被分割成多个块,,每个块称作一页或页面。每一页有连续的地址范围。这些页被映射到物理内存,但并不是所有的页都必须在内存中才能运行程序。当程序引用到一部分在物理内存中的地址时,有硬件立刻执行必要的映射。当程序引用到一部分不在内存中的地址空间时,有操作系统负责将缺失的部分装入物理内存并重新执行失败的指令。
在动态分区的存储空间中,存在“碎片”问题。尽管采用“紧凑”技术可以解决这个问题,但要为移动大量信息花去不少处理机时间,代价较高。
- 解决:如果允许将一个进程直接分散地分配到许多不相邻的分区中,就不比再进行“紧凑”。这就是离散分配方式。
- 根据离散分配所用单位的不同,分为
- 分页存储管理
- 分段存储管理
- 段页式存储管理
分页存储管理
分页存储管理是将一个进程的逻辑地址空间分为若干个大小相等的片,称为页面或页,并为各页加以编号,从 0 开始,如第 1 页。相应地把内存空间分成与页面相同大小的若干存储块,称为(物理)块或页框,为它们编号如 0#块。
在为进程分配内存时,以块为单位将进程中的若干页分别装入到多个可以不相邻的物理块中。
由于进程的最后一页经常装不满一块而形成了不可利用的碎片,称为“页内碎片”。
在分页系统中的页面大小应适中,通常为 512B~8kB。
- 页面太小:
- 可以使内存碎片减小,从而减少了内存碎片的总空间,有利于提高内存利用率;
- 使每个进程占用较多的页面,从而导致进程的页表过长,占用大量内存。还会降低页面换进换出的效率。
- 页面太大:
- 可以减少页表的长度,提高页面换进换出的速度,但会使页内碎片增大。
地址映射
程序地址空间中的各个页面被装到主存中的若干块中,由于这些块可能是不连续的,因此,为了保证程序的正确执行,必须进行动态地址映射。
在分页存储中,实现地址映射的结构称为页面映射表,简称页表。最简单的页表只是虚拟页与内存物理块的对照表。
虚拟地址结构:高位表示该地址所在的页号,低位表示该地址在这页内的相对位移。
现在的大多数计算机系统都支持非常大的逻辑地址空间(2^32~2^64),页表就变得非常大,要占用相当大的内存空间。
-
解决:
- 只将当前需要的部分页表项调入内存,其余的页表项仍驻留在磁盘上,需要时再调入。
- 采用离散分配方式来解决难以找到一块连续的大内存空间的问题。
- 快表
- 多级页表
-
页表可以存放在高速缓冲存储器中,地址变换速度快但成本高。(高配)
-
存放在内存固定区域,占用内存空间,而且地址变换速度较慢。(低配)
-
一部分存放在高速缓冲存储器中,一部分存放在内存中。(搭配)
快表 TLB
大多数程序总是对少量的页面进行多次访问,因此只有很少的页表项会被反复读取,而其他的页表项很少被访问。为计算机设置一个小型的硬件设备,将虚拟地址直接映射到物理地址,而不必访问页表。这种设备被称为转换检测缓冲区,也称为相联存储器或快表。
多级页表
引入分页思想。将页表进行分页,使每个页面的大小与内存物理块的大小相同,可以离散地将各个页面分别放在不同的物理块中。 新的问题是要为离散分配的页表再建立一张页表,称为外层页表,在每个页表项中记录页表页面的物理块号。
请调策略
当装入部分页面时,需要判断当前访问的页面是否在主存。当确认所访问的页面不在主存时,系统必须从辅存调入请求的页面,这就是请调策略。
允许一个程序只装入部分页面即可运行,进程在运行过程中必然会遇到所需代码或数据不在主存的情况,系统面临如下两个问题:
- 如何发现所访问的页面不在主存?
- 对不在主存的页面如何处理?
扩充页表的功能: 除页号和主存块号外增加中断位和辅存地址
- 中断位:识别该页是否在主存。0 是在主存,1 是不在
- 辅存地址:该页对应的辅存地址。
放置策略
确认程序的各个页面分配到主存的哪些块中,以及用什么原则挑选主存块。比非页式系统简单得多。
淘汰策略
当需要调入一个新页,而该作业所分得的主存块数全部用完时,需要确定那个页面应从主存中淘汰。
面临两个问题:
- 页面使用情况?新增改变位和引用位。
- 改变位:该页面是否被修改过。决定是否需要将该页数据写回辅存。
- 引用位:该页面最近被访问过没有。
- 淘汰策略/置换算法?当要放一页面到全满的主存块时,系统需淘汰一页。用来选取淘汰哪一页的规则叫置换算法。
- 最佳置换算法。是一种理论上的算法,其所选择的被淘汰页面是以后永不使用的或者在未来最长时间内不再被访问的页面。采用最佳置换算法,通常可保证获得最低的缺页率。由于在每个当前还无法预知哪个页面未来不被访问,因此该算法无法实现,但是可用于评价其他算法。
- 先进先出置换算法 FIFO。置换时选择在内存中驻留时间最长的页淘汰。FIFO 算法性能差的原因是只考虑页面调入内存的时间,而没有考虑页面的使用情况。改进:考虑使用情况换出以后不用的页面。由于无法预测页面将来的使用情况,只能用“最近的过去”作为“最近的将来”的近似,即最近最久未使用算法。
- 最近最久未用置换算法 LRU
- 近似的 LRU 算法(NRU 算法)
- 最不经常使用淘汰算法 LFU