第三章 内存空间的分配与回收
本文讨论没有使用虚拟存储技术的内存分配方式,包含 连续分配管理方式和 非连续分配管理方式。其中连续分配管理方式包括 单一连续分配、 固定分区分配和 动态分区分配。非连续分配管理方式包括 基本分页存储管理、 基本分段存储管理和 段页式存储管理
一、连续分配管理方式
连续分配:指为用户进程分配的必须是一个连续的内存空间。
外部碎片:外部碎片指的是还没有被分配出去(不属于任何进程),但由于太小了无法分配给申请内存空间的新进程的内存空闲区域。
内部碎片:分配给某进程的内存区域中,如果有些部分没有用上,就是“内部碎片”。
1.1 单一连续分配
在单一连续分配方式中,内存被分为系统区和用户区。系统区通常位于内存的低地址部分,用于存放操作系统相关数据;用户区用于存放用户进程相关数据。内存中只能有一道用户程序,用户程序独占整个用户区空间。
优点:实现简单;无外部碎片;
缺点:只能用于单用户、单任务的操作系统中;有内部碎片;存储器利用率极低。
1.2 固定分区分配
为了能在内存中装入多道程序,于是将整个用户空间划分为若干个固定大小的分区,在每个分区中只装入一道作业
固定分区分配有分区大小相等和分区大小不等两种
分区大小相等:缺乏灵活性,但是很适合用于用一台计算机控制多个相同对象的场合
分区大小不等:增加了灵活性,可以满足不同大小的进程需求。根据常在系统中运行的作业大小情况进行划分(比如:划分多个小分区、适量中等分区、少量大分区)
需要建立一个数据结构–分区说明表,每个表项对应一个分区,每个表项包含对应分区的大小、起始地址和状态(是否分配)
固定分区分配的优点:无外部碎片
固定分区分配的缺点:会产生内部碎片
1.3 动态分区分配
动态分区分配又称为可变分区分配。这种分配方式不会预先划分内存分区,而是在进程装入内存时,根据进程的大小动态地建立分区,并使分区的大小正好适合进程的需要。因此系统分区的大小和数目是可变的。
会有空闲分区表或空闲分区链
当出现两个相邻的空闲分区时,会合并为一个。
动态分区分配会涉及到进程的换入换出
动态分区分配没有内部碎片,但是有外部碎片。
小结:
动态分区分配算法
二、非连续分配管理方式
非连续分配:为用户进程分配的可以是一些分散的内存空间。
2.1 基本分页存储管理
2.1.1 什么是分页存储
内存空间:
分为一个个大小相等的分区(如:每个分区4KB),每个分区就是一个“页框”(页框=页帧=内存块=物理块=物理页面)。
每个页框有一个编号,即“页框号”(页框号=页帧号=内存块号=物理块号=物理页号),页框号从0开始。
进程的逻辑地址空间:
也分为与页框大小相等的一个个部分,每个部分称为一个“页”或“页面” 。
每个页面也有一个编号,即“页号”,页号也是从0开始
操作系统以页框为单位为各个进程分配内存空间。进程的每个页面分别放入一个页框中。也就是说,进程的页面与内存的页框有一一对应的关系。各个页面不必连续存放,可以放到不相邻的各个页框中。
注:进程的最后一个页面可能没有一个页框那么大。也就是说,分页存储有可能产生内部碎片,因此页框不能太大,否则可能产生过大的内部碎片造成浪费
2.1.2 重要的数据结构–页表
操作系统要为每个进程建立一张页表。
页表在PCB中,而PCB在内存的系统区
页表记录进程页面和实际存放的内存块之间的映射关系
每个页表项由“页号”和“块号”组成,页表的结构如下图所示,其中的页号是隐藏的,不占空间。
问题一:每个页表项占多少个字节?
页表项连续存放,因此页号可以是隐含的,不占存储空间(类比数组)
页表记录的只是内存块号,而不是内存块的起始地址!
仔细看上图的例题,算出了内存块号要用20bit来表示,而要考虑到实际情况,因此至少要3B来表示块号。
问题二:如何实现地址的转换?
即如何从逻辑地址A转换为物理地址B?
①根据逻辑地址A确定页号P(页面号)
页号 = 逻辑地址空间大小 / 页面空间大小(取除法的整数部分)
②根据逻辑地址A确定页内偏移量
页内偏移量 = 逻辑地址空间大小 % 页面空间大小(取除法的余数部分)
③根据页号查页表得到页框号(内存块号)
页框号后面加m个0,就得到了P号页面在内存中得起始地址(其中m为页内偏移量位数)
逻辑地址A 对应的物理地址 = P号页面在内存中的起始地址+页内偏移量W
小结
2.1.3 基本地址变换机构
理解基本地址变换机构(用于实现逻辑地址到物理地址转换的一组硬件机构)的原理和流程
基本地址变换机构可以借助进程的页表将逻辑地址转换为物理地址。
通常会在系统中设置一个页表寄存器(PTR),存放页表在内存中的起始地址F 和页表长度M。进程未执行时,页表的始址 和 页表长度 放在进程控制块(PCB)中,当进程被调度时,操作系统内核会把它们放到页表寄存器中。
整个地址变换过程均是硬件自动完成的。
设页面大小为L,逻辑地址A到物理地址E的变换过程如下:
仔细看上图过程!!!
在分页存储管理(页式管理)的系统中,只要确定了每个页面的大小,逻辑地址结构就确定了。因此,页式管理中地址是一维的。即,只要给出一个逻辑地址,系统就可以自动地算出页号、页内偏移量两个部分,并不需要显式地告诉系统这个逻辑地址中,页内偏移量占多少位。
小结
2.1.4 具有块表的地址变换机构
什么是快表
快表,又称联想寄存器(TLB ),是一种访问速度比内存快很多的高速缓存(TLB不是内存!),用来存放最近访问的页表项的副本,可以加速地址变换的速度。与此对应,内存中的页表常称为慢表。
若快表命中,则整个过程只需一次访存,若未命中快表,则需要两次访存。
未命中情况下,在找到页表项后,应同时将其存入快表,以便后面可能的再次访问。但若快表已满,则必须按照一定的算法对旧的页表项进行替换
仔细看上图!!!!
2.1.5 两级页表
单极页表存在什么问题,如何解决?
问题一:页表必须连续存放,因此当页表很大时,需要占用很多个连续的页框。
问题二:没有必要让整个页表常驻内存,因为进程在一段时间内可能只需要访问某几个特定的页面。(这个问题引入了虚拟存储技术后再解决)
如何解决:引入两级页表
两级页表的原理、逻辑地址结构
这里的由顶级页表中的内存块号找二级页表的起始地址的方法 与 由二级页表的内存块号找块在实际内存中的起始物理地址的方法一样,都是内存块号逻辑左移,页内偏移量是几位就逻辑左移几位
如何实现地址变换
需要注意的两个细节
①一般来说各级页表的大小不能超过一个页面
② 两级页表的访存次数分析(假设没有快表机构)
第一次访存:访问内存中的页目录表
第二次访存:访问内存中的二级页表
第三次访存:访问目标内存单元
共三次访存
小结
2.2 基本分段存储管理
什么是分段
进程的地址空间:按照程序自身的逻辑关系划分为若干个段,每个段都有一个段名(在低级语言中,程序员使用段名来编程),每段从0开始编址
内存分配规则:以段为单位进行分配,每个段在内存中占据连续空间,但各段之间可以不相邻
段号的位数决定了每个进程最多可以分几个段
段内地址位数决定了每个段的最大长度是多少
什么是段表
①每个段对应一个段表项,其中记录了该段在内存中的起始位置(又称“基址”)和段的长度。
②每个段表项的长度是相同的。因此段号可以是隐含的,不占存储空间。
如何实现地址变换
注意,分段管理需要这一步:
检查段内地址是否超过段长。若W≥C,则产生越界中断,否则继续执行
分段、分页管理对比
页是信息的物理单位。分页的主要目的是为了实现离散分配,提高内存利用率。
段是信息的逻辑单位。分段的主要目的是更好地满足用户需求。
页的大小固定且由系统决定。段的长度却不固定,决定于用户编写的程序。
分页的用户进程地址空间是一维的
分段的用户进程地址空间是二维的
分段比分页更容易实现信息的共享和保护。
小结
2.3 段页式存储管理
可以对比两级分页来学习
分页、分段管理方式中最大的优缺点
段式管理会产生外部碎片的机理跟动态分区分配产生外部碎片的机理一样。
段页式管理方式
先分段,再分页
段号的位数决定了每个进程最多可以分几个段
页号位数决定了每个段最大有多少页
页内偏移量决定了页面大小、内存块大小是多少
“分段”对用户是可见的,程序员编程时需要显式地给出段号、段内地址。而将各段“分页”对用户是不可见的。系统会根据段内地址自动划分页号和页内偏移量。
段页式管理的地址结构是二维的。
段表、页表
这里的段表与段式管理中的段表不同,仔细看上图。
如何实现地址变换
共三次访存
也可引入快表机构,用段号和页号作为查询快表的关键字。若快表命中则仅需一次访存
小结