本章目标:
所以,之后要介绍的分页和分段,都是基于内存的管理技术,是为了管理内存
内存是现代计算机运行的中心。CPU根据程序计数器PC的值从内存中提取指令,这些指令可能会引起进一步对特定内存地址的读取和写入
基地址和界限地址寄存器
为了确保每个进程都有独立的内存空间,需要确保进程可访问的合法地址的范围,并确保进程只访问其合法地址
基地址寄存器含有最小的合法物理内存地址,界限地址寄存器决定了范围的大小
内存空间保护的实现,是通过CPU硬件对用户模式所产生的每一个地址与寄存器的地址进行比较来完成的。
如果在用户模式下执行的程序试图越过界限,访问其它部分的内存,则会陷入到操作系统,并作为致命错误处理
只有操作系统可以通过特殊的特权指令来修改和加载基地址寄存器和界限地址寄存器
程序以二进制可执行文件的形式存储在磁盘上。为了执行,程序被调入内存并放在进程空间内。
在磁盘等待调入内存以便执行的进程形成输入队列
许多系统允许用户进程放在物理内存的任意位置。而从磁盘调入内存的过程中需要地址绑定的过程
虽然现代计算机的地址空间从00000开始,但是用户进程的开始地址不一定是00000。用户程序执行之前,需要经过好几个步骤,其中有的步骤是可选的,这些步骤中,地址可能有不同的表示形式,源程序中的地址通常是用符号来表示的。
编译器常常将这些符号地址绑定在可重定位的地址
将指令与数据绑定到内存地址有以下几种情况
CPU所生成的地址通常称为逻辑地址,而内存单元所看到的地址(加载到内存地址寄存器中的地址)通常称为物理地址
编译和加载时的地址绑定方法生成相同的逻辑地址和物理地址,但是,执行时的地址绑定方案将导致不同的逻辑地址和物理地址
通常称逻辑地址为虚拟地址,本书中逻辑地址 = 虚拟地址
运行时从虚拟地址到物理地址的映射是由**内存管理单元(MMU)**这个部件完成的
这种映射方法是对基地址寄存器方案的推广,基地址寄存器在这里被称为重定位寄存器
用户进程所生成的地址在送交内存之前,都将加上重定位寄存器的值
这一部分内容老师说会和第9章的内容结合起来讲,暂时跳过了
内存通常分为两个区域,一个用于驻留操作系统,另一个用于用户进程
通常需要将多个进程同时放在内存中,因此需要考虑如何为输入队列中需要调入内存的进程分配内存空间。采用连续内存分配时,每个进程位于一个连续的内存区域
采用重定向寄存器和界限地址寄存器可以实现对内存的保护
重定向寄存器含有最小的物理地址值,界限地址寄存器含有逻辑地址的范围值
外部碎片问题:随着进程装入和移出内存,空闲内存空间被分为小片段。当总的可用内存之和可以满足请求,但并不连续时,就出现了外部碎片问题。这个问题可能导致内存浪费
解决外部碎片问题的方法
分页内存管理方案允许进程的物理地址空间可以是非连续的
在分页这种方法中,将物理内存分为固定大小的块,称为帧
同时将逻辑内存也分为同样大小的块,称为页
当需要执行进程时,页从备份存储中调入到可用的内存帧中
CPU生成的地址分为两个部分:页号(p)和页偏移(d)
页号作为页表中的索引,页表包含每页所在物理内存的基地址,这些基地址与页偏移的组合形成了物理地址
页大小通常由硬件决定,页的大小通常为2的幂
如果逻辑地址的空间为2^m
页的大小为2^n单元
则逻辑地址的高m-n位表示页号,低n位表示页偏移
关于逻辑内存映射到物理内存的过程,书上有,要求完全掌握
当系统进程需要执行时,它将检查该进程的大小(按页计算),进程的每页都需要一帧
分页的一个重要特点是实现用户视角的内存和实际的物理内存的分离。用户程序将内存作为一整块来处理,只包括这一个进程。
事实上,一个用户程序与其它程序一起,分布在物理内存上。用户视角的内存和实际的物理内存的差异是通过地址转换硬件协调的,将逻辑地址转换为物理地址。这种转换受操作系统控制
绝大多数操作系统都为每个进程分配一个页表。
页表的硬件实现由多种方法
采用第二种方法会导致一个问题,一个字节需要两次访存才能取出(一次用于找页表条目,一次用于字节)
为了解决这个问题,使用了一种快速硬件缓冲,这种缓冲称为转换表缓冲区(TLB)。TLB是关联的快速内存。
TLB由键值对组成。采用这种方式可以快速访问页表(和Cache类似)
页号在TLB中被查找到的百分比被称为命中率
在分页环境下,内存保护是通过每个帧相关联的保护位来实现的。这些保护位存储在页表中
在页表中,会定义一个位,用来指定该页是可读写的还是只读的
这个位被称为有效-无效位(valid-invalid)
当该位为有效时,表示相关的页在进程的逻辑地址空间内。
当该位为无效时,表示相关的页不在进程的逻辑地址空间里
可以通过使用有效-无效位捕捉到非法地址
分页的优点之一在于可以共享公共代码,可以实现重用代码
下面这个图清晰地演示了分页环境下的代码共享
在现代计算机系统里,页表往往非常大,不可能在内存中分配这么大的一个连续空间用来存储页表。
一个简单的方法是将页表划分为更小的部分。
两级分页法
以4KB页大小的32位系统为例,一个逻辑地址被分为20位的页码和12位的页偏移。因为要对页表再分页,所以该页号可以分为10位的页码和10位的页偏移
p1是用来访问外部页表的索引,p2是外部页表的页偏移
这种方案也被称为向前映射页表
哈希页表常被用于处理超32位的地址空间,并以虚拟页码作为哈希值
哈希页表的每一条目都包括一个链表的元素,这些元素的哈希值相同
每个链表元素有三个域
从这张图上可以看到,哈希表实际上使用的数组+链表组合的形式用于存储相应的页
这部分内容不是重点,期末再来整理
采用分页的方法会导致用户视角地内存和实际物理内存的分离。
用户视角的内存需要映射到实际物理内存,该映射允许区分逻辑内存和物理内存
通常情况下,我们会将内存看作一组不同长度的段的集合,这些段之间并没有一定的顺序
实际地址映射是通过段表实现的。
段表的每个条目都有段基地址和段界限,段基地址包含该段在内存中的开始物理地址,而段界限指定该段的长度
关于段的硬件原理,具体看这张图
具体的例子可以看这张图