【操作系统-内存】内存的分配和管理方式
1 连续分配方式
- 内部碎片:分配给某进程的内存区域中,但有些部分没有用上
- 外部碎片:指内存中的某些空闲分区由于太小而难以利用,可以通过紧凑(拼凑,Compaction)技术来解决外部碎片
1.1 单一连续分配
如早期的 PC 操作系统 MS-DOS,内存中只能有一道用户程序,用户程序独占整个用户区空间。优缺点:
- 优点:实现简单;无外部碎片;可以采用覆盖技术扩充内存;不一定需要采取内存保护
- 缺点:只能用于单用户、单任务的操作系统中;有内部碎片;存储器利用率极低
1.2 固定分区分配
将整个用户空间划分为若干个固定大小的分区,在每个分区中只装入一道作业。两种分配方案:
- 分区大小相等:缺乏灵活性,但是很适合用于用一台计算机控制多个相同对象的场合
- 分区大小不等:增加了灵活性,可以满足不同大小的进程需求。根据常在系统中运行的作业大小情况进行划分(比如:划分多个小分区、适量中等分区、少量大分区)
操作系统需要建立一个分区说明表,来实现各个分区的分配与回收。每个表项对应一个分区,通常按分区大小排列。每个表项包括对应分区的大小、起始地址、状态(是否已分配)。
优缺点:
- 优点:实现简单,无外部碎片
- 缺点:a. 当用户程序太大时,可能所有的分区都不能满足需求,此时不得不采用覆盖技术来解决,但这又会降低性能;b. 会产生内部碎片,内存利用率低
1.3 动态分区分配
动态分区分配又称为可变分区分配。这种分配方式不会预先划分内存分区,而是在进程装入内存时,根据进程的大小动态地建立分区,并使分区的大小正好适合进程的需要。因此系统分区的大小和数目是可变的。动态分区分配没有内部碎片,但是有外部碎片。
操作系统可使用两种方案记录空闲分区的情况:
- 空闲分区表:每个空闲分区对应一个表项。表项中包含分区号、分区大小、分区起始地址等信息
- 空闲分区链:每个分区的起始部分和末尾部分分别设置前向指针和后向指针。起始部分处还可记录分区大小等信息
1.3.0 空闲分区的回收
空闲分区的回收分为四种情况:
- 回收区的后面有一个相邻的空闲分区:回收后,两个相邻的空闲分区合并为一个,空闲分区表需修改对应的表项
- 回收区的前面有一个相邻的空闲分区:回收后,两个相邻的空闲分区合并为一个,空闲分区表需修改对应的表项
- 回收区的前、后各有一个相邻的空闲分区:回收后,三个相邻的空闲分区合并为一个,空闲分区表需修改对应的表项
- 回收区的前、后都没有相邻的空闲分区:回收后,空闲分区多一个,空闲分区表需新增一个表项
把一个新作业装入内存时,须按照一定的动态分区分配算法,从空闲分区表(或空闲分区链)中选出一个分区分配给该作业,不过这些算法的性能都非常差。
1.3.1 首次适应算法
首次:找到第一个能放得下的空闲分区
- 查找空闲分区的思路:每次都从低地址开始查找,找到第一个能满足大小的空闲分区
- 实现方法:空闲分区以地址递增的次序排列。每次分配内存时顺序查找空闲分区链(或空闲分区表),找到大小能满足要求的第一个空闲分区
- 优点:算法开销小,综合四种算法来看,邻近适应算法性能最好
1.3.2 邻近适应算法
邻近:继续查找
- 查找空闲分区的思路:每次都从上次查找结束的位置开始检索
- 实现方法:空闲分区以地址递增的顺序排列(可排成一个循环链表)。每次分配内存时从上次查找结束的位置开始查找空闲分区链(或空闲分区表),找到大小能满足要求的第一个空闲分区
- 优点:算法开销小,不用每次都从低地址的小分区开始检索
- 缺点:会使高地址的大分区也被用完
1.3.3 最佳适应算法
最佳:找到刚好放得下的空闲分区
- 查找空闲分区的思路:优先使用更小的空闲区
- 实现方法:空闲分区按容量递增次序链接。每次分配内存时顺序查找空闲分区链(或空闲分区表),找到大小能满足要求的第一个空闲分区
- 优点:会有更多的大分区被保留下来,更能满足大进程需求
- 缺点:每次都选最小的分区进行分配,会留下越来越多的、很小的、难以利用的内存块。因此这种方法会产生很多的外部碎片;需要排序,算法开销大
1.3.4 最坏(最大)适应算法
最坏:找到最大的空闲分区
- 查找空闲分区的思路:在每次分配时优先使用最大的连续空闲区,这样分配后剩余的空闲区就不会太小,更方便使用
- 实现方法:空闲分区按容量递减次序链接。每次分配内存时顺序查找空闲分区链(或空闲分区表),找到大小能满足要求的第一个空闲分区
- 优点:可以减少难以利用的小碎片
- 缺点:每次都选最大的分区进行分配,虽然可以让分配后留下的空闲区更大,更可用,但是这种方式会导致较大的连续空闲区被迅速用完。如果之后有“大进程”到达,就没有内存分区可用了;需要排序,算法开销大
2 分页存储管理
2.1 一级基本分页存储管理
假设逻辑地址空间为 32 位(4GB),一页为 4KB,物理地址空间为 28 位(256MB),则:
2.1.1 物理地址空间
将内存空间分为一个个大小相等的分区(每个分区 4KB),每个分区就是一个“页框”。每个页框有一个编号,即“页框号”。页框号从 0 开始。
物理地址空间中页框和页框号的概念:
- 页框 = 页帧 = 内存块 = 物理块 = 物理页面
- 页框号 = 页帧号 = 内存块号 = 物理块号 = 物理页号
物理地址空间的分区如下(228/212 = 216 个页框):
页框号 | 页框大小 |
---|---|
页框号 0 | 4KB |
页框号 1 | 4KB |
页框号 2 | 4KB |
页框号 3 | 4KB |
... | ... |
页框号 216-1 | 4KB |
2.1.2 逻辑地址空间
将进程的逻辑地址空间也分为与页框大小相等的一个个部分,每个部分称为一个“页”或“页面” 。每个页面也有一个编号,即“页号”,页号也是从 0 开始。进程的页面与内存的页框有一一对应的关系。
如何理解“一一对应”这个字眼?一个页面可以对应(更准确来讲是“映射”)一个页框,但不可以对应多个页框;但一个页框可以对应多个页面(这里可引申出虚拟映射文件技术)。比如,页号 0 的页面可以对应页框号 6 的页框,页号 1 的页面可以对应页框号 5 的页框,页号 2 的页面可以对应页框号 4 的页框等等;框号 4 的页框可以同时对应页号 2 的页面和页号 8 的页面。
逻辑地址空间中页和页号的概念:
- 页 = 页面
- 页号 = 虚页号
- 虚拟内存的实际硬件是不存在的,实际上是由页表来描述页面和页框之间的映射关系
逻辑地址空间的分区如下(232/212 = 220 个页):
页面 | 页面大小 |
---|---|
页号 0 | 4KB |
页号 1 | 4KB |
页号 2 | 4KB |
页号 3 | 4KB |
... | ... |
页号 220-1 | 4KB |
2.1.3 地址结构
逻辑地址结构:
- 页内地址(页内偏移量):位数的多少指示每个页的大小;本身可指示页内偏移量
- 逻辑页号:位数的多少指示整个地址空间被划分为多少页
逻辑页号 | 页内地址/页内偏移量 |
---|---|
20b | 12b |
物理地址结构:
- 页内地址(页内偏移量):位数的多少指示每个页的大小;本身可指示页内偏移量
- 物理页号:位数的多少指示整个地址空间被划分为多少页
物理页号 | 页内地址/页内偏移量 |
---|---|
16b | 12b |
2.1.4 页表和页表项
- 一个进程对应一张页表
- 进程的每个页面对应一个页表项
- 每个页表项由“页号”和“物理页号(页框号、块号)”组成,注意虚页号不属于页表结构,所以加括号
- 页表记录进程页面和实际存放的内存块之间的映射关系
- 每个页表项的长度是相同的
页表寄存器(PTR) 的结构:
页表起始地址 | 页表长度 |
---|---|
记录页表存放的首地址(物理地址) | 记录一个页表能放下多少个页表项(这里存储十进制 220) |
一个页表项的结构(因为物理地址空间有 216 个页,所以页表项的物理页号占 16 位):
(页号) | 物理页号(页框号/块号) |
---|---|
实际不需要记录页号 | 该页实际对应的物理页号(页框号),占 16b |
页表的结构(因为逻辑地址空间有 220 个页,所以页表有 220 个页表项)(举个例子:页号 0 的页面映射页框号 6 的页框,页号 1 的页面映射页框号 5 的页框,页号 2 的页面映射页框号 3 的页框,页号 3 的页面映射页框号 3 的页框,则如下表所示):
(页号) | 物理页号(页框号/块号) |
---|---|
(0) | 16b(存储页框号 6,对应二进制 0000,0000,0000,0110) |
(1) | 16b(存储页框号 5,对应二进制 0000,0000,0000,0101) |
(2) | 16b(存储页框号 3,对应二进制 0000,0000,0000,0011) |
(3) | 16b(存储页框号 3,对应二进制 0000,0000,0000,0011) |
... | ... |
(220-1) | 16b(存储页框号 ...) |
这个页表大小为 220*2B = 221B = 2MB。因为一个页是 4KB,所以这样一个页表需要占据 2MB/4KB = 211KB/4KB = 29 = 128 页。
2.1.5 TLB 结构
快表,又称相联寄存器,是一种访问速度比内存快很多的高速缓存(TLB不是内存!),用来存放最近访问的页表项的副本,可以加速地址变换的速度。与此对应,内存中的页表常称为慢表。
TLB 的结构跟页表差不多,只是 TLB 需要多存储“页号”即标记位。
页号 | 物理页号(页框号/块号) |
---|---|
2 | xxx(16b) |
4 | xxx(16b) |
15 | xxx(16b) |
... | ... |
2.1.6 地址变换过程
(1)根据逻辑地址计算出页号、页内偏移量:
- 逻辑地址为十进制:
页号 = 逻辑地址 / 页面大小
,页内偏移量 = 逻辑地址 % 页面大小
- 逻辑地址为二进制且页面大小是 2 的整数幂(假设逻辑地址空间的总页数为 2x):
页号 = 逻辑地址高 x 位
,页内偏移量 = 逻辑地址剩余位
(2)判断页号是否越界:
- 页表寄存器(PTR):记录页表起始地址和页表长度
- 比较页号和页表长度:若
页号 ≥ 页表长度
,发生越界中断,立即终止;若页号 < 页表长度
,则没有越界
(3)查询页表:通过 PTR 的页表访问内存,起始地址找到页号对应的页表项,确定页面存放的页框号(内存块号)
(4)用页框号(内存块号)和页内偏移量得到物理地址:
- 逻辑地址为十进制:
物理地址 = 页框号 * 页面大小 + 页内偏移量
- 逻辑地址为二进制且页面大小是 2 的整数幂(假设逻辑地址空间的总页数为 2x):
物理地址 = 页框号 拼接 页内偏移量
(把逻辑地址的高 x 位地址换成页框号即可得到物理地址)
(5)访问目标内存单元
2.1.7 有 TLB 的地址变换过程
(1)根据逻辑地址计算出页号、页内偏移量:
- 逻辑地址为十进制:
页号 = 逻辑地址 / 页面大小
,页内偏移量 = 逻辑地址 % 页面大小
- 逻辑地址为二进制且页面大小是 2 的整数幂(假设逻辑地址空间的总页数为 2x):
页号 = 逻辑地址高 x 位
,页内偏移量 = 逻辑地址剩余位
(2)判断页号是否越界:
- 页表寄存器(PTR):记录页表起始地址和页表长度
- 比较页号和页表长度:若
页号 ≥ 页表长度
,发生越界中断,立即终止;若页号 < 页表长度
,则没有越界
(3)查询快表:若在 TLB 中找到页号对应的页表项,则可确定页面存放的页框号(内存块号),直接到第(5)步;若没有找到,则进行第(4)步
(4)查询页表:通过 PTR 的页表起始地址访问内存,找到页号对应的页表项,确定页面存放的页框号(内存块号)
(5)用页框号(内存块号)和页内偏移量得到物理地址:
- 逻辑地址为十进制:
物理地址 = 页框号 * 页面大小 + 页内偏移量
- 逻辑地址为二进制且页面大小是 2 的整数幂(假设逻辑地址空间的总页数为 2x):
物理地址 = 页框号 拼接 页内偏移量
(把逻辑地址的高 x 位地址换成页框号即可得到物理地址)
(6)访问目标内存单元
2.2 二级基本分页存储管理
假设逻辑地址空间为 32 位(4GB),一页为 4KB,物理地址空间为 28 位(256MB),所以逻辑地址空间被分为 232/212 = 220 个页,物理地址空间被分为 228/212 = 216 个页框。
现继续假设规定页表项长度为 16b = 2B(不同级页表的页表项长度都是固定的),所以一个页能存储 4KB/2B = 2K = 211 个页表项。而又因为逻辑地址空间被分为 220 个页,即总共需要 220 个页表项,从而进一步计算 20/11 = 2(向上取整),分页系统需要分两级。
需要怎么分呢?通常规定:一个页目录表只能占据一个页面,所以一个页目录表可以映射 211 个二级页表,那么每个二级页表就存储 29 个页表项。
2.2.1 地址结构
逻辑地址结构:
- 页内地址(页内偏移量):位数的多少指示每个页的大小;本身可指示页内偏移量
- 顶级 + 二级逻辑页号:位数的多少指示整个地址空间被划分为多少页
顶级逻辑页号 | 二级逻辑页号 | 页内地址/页内偏移量 |
---|---|---|
11b | 9b | 12b |
物理地址结构:
- 页内地址(页内偏移量):位数的多少指示每个页的大小;本身可指示页内偏移量
- 物理页号:位数的多少指示整个地址空间被划分为多少页
物理页号 | 页内地址/页内偏移量 |
---|---|
16b | 12b |
2.2.2 页目录表(顶级页表)和页目录表项
页目录表寄存器(PDBR) 的结构:
页目录表起始地址 | 页表长度 |
---|---|
记录页目录表存放的首地址(物理地址) | 记录一个页表能放下多少个页目录表项 |
一个页目录表项的结构:
(页号) | 物理页号(页框号/块号) |
---|---|
实际不需要记录页号 | 记录页表存放的页框号(物理块号),占据 16b |
页目录表的结构:
(页号) | 物理页号(页框号/块号) |
---|---|
(0) | 16b |
(1) | 16b |
(2) | 16b |
(3) | 16b |
... | ... |
(211-1) | 16b |
2.2.3 页表(二级页表)和页表项
由以上页目录表可以看出,二级页表一共有 211 个。
页表基地址的组成:
物理页号 | 页内地址/页内偏移量 |
---|---|
16b(注意该项来源于页目录表项!) | 12b |
一个页表项的结构:
(页号) | 物理页号(页框号/块号) |
---|---|
实际不需要记录页号 | 该页实际对应的物理页号(页框号),占据 16b |
页表的结构:
(页号) | 物理页号(页框号/块号) |
---|---|
(0) | 16b |
(1) | 16b |
(2) | 16b |
(3) | 16b |
... | ... |
(29-1) | 16b |
这个页表大小为 29*2B = 1KB。因为一共有 211 个页表,所以这些二级页表总共占据 211*1KB = 2MB。
2.2.4 地址变换过程
(1)按照地址结构将逻辑地址拆分成三部分
(2)从 PDBR 中读出页目录表始址,再根据顶级页号查页目录表(访存 1 次),找到对应二级页表在内存中的存放位置
(3)根据二级页号查二级页表(访存 2 次),找到最终想访问的内存块号
(4)结合页内偏移量得到物理地址
(5)访问目标内存单元(访存 3 次)
2.3 请求分页虚拟存储管理
2.3.1 页表和页表项
一个页表项的结构:
(页号) | 物理页号(页框号/块号) | 状态位 | 访问字段 | 修改位(脏位) | 外存地址 |
---|---|---|---|---|---|
实际不需要记录页号 | 该页实际对应的物理页号(页框号) | 指示该页是否调入内存,供程序访问时参考 | 记录该页在一段时间内被访问的次数 | 指示该页在调入内存后是否被修改过,以确定页面置换时是否写回外存 | 存储该页在外存的地址,供调入该页时使用 |
页表的结构:
(页号) | 物理页号(页框号/块号) | 状态位 | 访问字段 | 修改位(脏位) | 外存地址 |
---|---|---|---|---|---|
(0) | ... | ||||
(1) | ... | ||||
(2) | ... | ||||
(3) | ... | ||||
... | ... | ||||
(...) | ... |
2.3.2 TLB 结构
TLB 的结构跟页表差不多,只是 TLB 需要多存储“页号”即标记位。
页号 | 物理页号(页框号/块号) | 状态位 | 访问字段 | 修改位(脏位) | 外存地址 |
---|---|---|---|---|---|
1 | ... | ||||
7 | ... | ||||
2 | ... | ||||
9 | ... | ||||
... | ... |
2.3.3 地址变换过程 + 缺页中断过程
(1)根据逻辑地址计算出页号、页内偏移量
(2)判断页号是否越界:若判断越界,则发生越界中断,立即终止
(3)查询快表:若在 TLB 中找到页号对应的页表项,则可确定页面存放的页框号(内存块号),直接到第(5)步;若没有找到,则进行第(4)步
(4)查询页表:通过 PTR 的页表起始地址访问内存,若找到页号对应的页表项,则确定页面存放的页框号(内存块号),直接到第(6)步;若没有找到,则进行第(5)步
(5)缺页中断处理:
(5-1)在外存中找到该缺页
(5-2)判断内存是否已满:若是,选择一页换出(还需判断该页是否被修改过,若是,先将其写入外存);若不是,直接进行(5-3)步
(5-3)将该缺页从外存读入内存
(5-4)修改页表,修改 TLB
(6)修改访问位和修改位
(7)用页框号(内存块号)和页内偏移量得到物理地址
(8)访问目标内存单元
2.4 基本分页与请求分页的区别
请求分页存储管理与基本分页存储管理的主要区别:
在程序执行过程中,当所访问的信息不在内存时,由操作系统负责将所需信息从外存调入内存,然后继续执行程序。
若内存空间不够,由操作系统负责将内存中暂时用不到的信息换出到外存。
【注】虚拟内存需要满足两个条件:
- 虚拟内存的实际容量 ≤ 内存容量 + 外存容量
- 虚拟内存的最大容量 ≤ 计算机的地址位数能容纳的最大容量
3 分段存储管理
段:进程的地址空间按照程序自身的逻辑关系划分为若干个段,每个段都有一个段名(在低级语言中,程序员使用段名来编程),每段从 0 开始编址。每个段在内存中占据连续空间,但各段之间可以不相邻。
3.1 逻辑地址空间
以实际例子说明分段存储管理的结构,某个进程的地址空间划分段如下:
段号 0 |
---|
程序段 4KB |
段号 1 |
---|
数据段 1KB |
段号 2 |
---|
堆栈段 2KB |
段号 3 |
---|
数据段 2KB |
3.2 物理地址空间
物理内存存放各个段的位置如下:
地址 | 内容 |
---|---|
... | ... |
40K-70K | (段号 0)程序段 4KB |
... | ... |
100K-102K | (段号 3)数据段 2KB |
... | ... |
159K-160K | (段号 1)数据段 1KB |
... | ... |
214K-216K | (段号 2)堆栈段 2KB |
... | ... |
3.3 段表和段表项
段表寄存器的结构:
段表起始地址 | 段表长度 |
---|---|
记录段表存放的首地址(物理地址) | 记录一个段表能放下多少个段表项 |
一个段表项的结构:
(段号) | 段长 | 段基址 |
---|---|---|
实际不需要记录段号 | 记录该段最大可以多长 | 记录该段的首地址(物理地址) |
段表的结构(可对照物理地址空间):
(段号) | 段长 | 段基址 |
---|---|---|
(0) | 4KB | 40K |
(1) | 1KB | 159K |
(2) | 2KB | 214K |
(3) | 2KB | 100K |
... | ... | ... |
3.4 地址结构
逻辑地址结构:
- 段号:段号的位数决定了每个进程最多可以分几个段
- 段内偏移量:段内地址位数决定了每个段的最大长度是多少
(若要访问程序段的地址 8B 处,假设逻辑地址是 13 位,给出例子如下)
段号 | 段内偏移量 |
---|---|
0 | 0000,0000,1000 |
物理地址结构:
- 段的首地址:该段在内存中的实际起始位置
- 段内偏移量:在段内的位置
(继续上面的例子,则通过查段表,可得到物理地址如下)
段的首地址 | 段内偏移量 |
---|---|
40K | 0000,0000,1000 |
3.5 地址变换过程
(1)根据逻辑地址得到段号、段内偏移量:高位为段号,低位为段内偏移量
(2)判断段号是否越界:
- 段表寄存器:记录段表起始地址和段表长度
- 比较段号和段表长度:若
段号 ≥ 段表长度
,发生越界中断,立即终止;若段号 < 段表长度
,则没有越界
(3)查询段表:通过段表寄存器访问所指向的段表,找到段号对应的段表项,确定段基址
(4)用段基址和段内偏移量得到物理地址:
- 逻辑地址为十进制:
物理地址 = 段基址 + 段内偏移量
- 逻辑地址为二进制:
物理地址 = 段基址 拼接 段内偏移量
(把逻辑地址的高 x 位地址换成段基址即可得到物理地址)
(5)访问目标内存单元
3.6 分段与分页的区别
项目 | 分页 | 分段 |
---|---|---|
目的 | 系统管理的需要,提高内存利用率 | 用户的需求,用户编程时需要显式地给出段名 |
长度 | 页的大小固定且由系统决定 | 段的长度却不固定,决定于用户编写的程序 |
地址空间 | 进程地址空间是一维的,程序员只需给出一个记忆符即可表示一个地址 | 进程地址空间是二维的,程序员在标识一个地址时,既要给出段名,也要给出段内地址 |
碎片 | 只有内部碎片 | 只有外部碎片 |
4 段页式存储管理
假设某进程最多可以分 256 个段,页面大小为 4KB,页表有 210 个页表项。
4.1 逻辑地址空间
将进程按逻辑模块分段,再将各段分页(各段均从 0 页开始),再将内存空间分为大小相同的内存块,将各页面分别装入各内存块中。假设逻辑地址空间如下:
段号 0(程序段 10KB) |
---|
0 号页(4KB) |
1 号页(4KB) |
2 号页(2KB) |
段号 1(数据段 6KB) |
---|
0 号页(4KB) |
1 号页(2KB) |
段号 2(堆栈段 2KB) |
---|
0 号页(2KB) |
4.2 物理地址空间
假设各个段及其页表映射到物理地址空间的位置如下:
页框 | 内容 |
---|---|
页框号 0 | 程序段(1) 4KB |
页框号 1 | 无 |
页框号 2 | 程序段(3) 2KB |
页框号 3 | 无 |
... | ... |
页框号 7 | 数据段(2) 2KB |
页框号 8 | 程序段(2) 4KB |
页框号 9 | 数据段(1) 4KB |
... | ... |
页框号 15 | 堆栈段 2KB |
... | ... |
页框号 25 | 程序段的页表 4KB |
页框号 26 | 数据段的页表 4KB |
页框号 27 | 堆栈段的页表 4KB |
... | ... |
4.3 段表和页表
每个进程只有一张段表,根据上面的映射情况,段表中存储如下:
(段号) | 页表长度 | 页表存放块号 |
---|---|---|
(0) | 3 | 25 |
(1) | 2 | 26 |
(2) | 1 | 27 |
... | ... | ... |
每个段都有自己的页表,根据上面的映射情况,这三个段的页表中存储如下:
- 段号 0(程序段 10KB)的页表:
(页号) | 页框号 |
---|---|
(0) | 0 |
(1) | 8 |
(2) | 2 |
... | ... |
- 段号 1(数据段 6KB)的页表:
(页号) | 页框号 |
---|---|
(0) | 9 |
(1) | 7 |
... | ... |
- 段号 2(堆栈段 2KB)的页表:
(页号) | 页框号 |
---|---|
(0) | 15 |
... | ... |
4.4 地址结构
(假设某进程最多可以分 256 个段,页面大小为 4KB,页表有 210 个页表项)
逻辑地址结构:由段号、页号、页内地址(页内偏移量)组成。
- 段号:段号的位数决定了每个进程最多可以分几个段
- 页号:页号位数决定了每个段最大有多少页
- 页内偏移量:页内偏移量决定了页面大小是多少
段号 | 页号 | 页内偏移量 |
---|---|---|
8b | 10b | 12b |
物理地址结构:
- 物理页号:实际在哪个物理页号/内存块号。
- 页内偏移量:在段内的位置
(假设访问程序段的 9KB 处,则对应 2 号页,2 号页框)
物理页号 | 页内偏移量 |
---|---|
2*4K=8K | 12b |
4.5 地址变换过程
(1)根据逻辑地址得到段号、页号、页内偏移量
【注】也可引入快表机构,用段号和页号作为查询快表的关键字。若快表命中则仅需一次访存
(2)判断段号是否越界:若段号 ≥ 段表长度
,发生越界中断,立即终止;若段号 < 段表长度
,则没有越界
(3)查询段表:通过段表寄存器,找到段表,找到对应的段表项,得到页表存放块号(即存放页表的起始页号)(第一次访存)
(4)检查页号是否越界:若页号 ≥ 页表长度
,发生越界中断,立即终止;若页号 < 页表长度
,则没有越界
(5)根据页表存放块号、页号查询页表,找到对应页表项:页表项地址 = 存放页表的起始页号*页面大小 + 页号*页表项长度
(第二次访存)
(6)根据内存块号、页内偏移量得到最终的物理地址:内存块号 拼接 页内偏移量
(7)访问目标内存单元(第三次访存)