物理寻址
主存(内存)
- 计算机主存也可以称为物理内存,内存可以看成由若干个连续字节大小的单元组成的数组
- 每个字节都有一个唯一的物理地址(Physical Address)
- CPU访问内存前,先拿到内存地址,然后,通过内存地址访问内存中数据指令
总线的分工
- 数据总线:负责传输实际数据的
- 地址总线:负责传输数据地址的,用来确定到底把数据传输到哪里去,是内存的某个位置,还是某一个 I/O 设备
- 控制总线:负责传输控制信号的,用于控制对于总线的访问
分段寻址
虚拟寻址
虚拟寻址(Virtual Addressing):
- CPU 通过虚拟地址 (Virtual Address,VA)来访问主存
- 虚拟地址(比如:段选择子 + 段内偏移) 在送到内存之前,先转换成适当的物理地址
- 将一个虚拟地址转换为物理地址的过程称为地址转换(Address Translation)
使用虚拟寻址的方式,可以起到内存保护的作用,使得每个程序的内存相互隔离,一个程序的内存不会被其他的程序破坏,从而可以实现,在内存中同时存储多个程序。
当然,虚拟寻址不止这一点优点,它还可以降低用户程序对内存使用的复杂度:
如果用户自己管理物理内存,太过于复杂,容易出现内存冲突问题,引入虚拟地址后,不同用户程序的虚拟地址是相互独立隔离的,用户只需要关心如何分配虚拟地址即可,由操作系统负责管理物理内存。
地址空间
地址空间 (address space)是一个非负整数地址的有序集合,比如{0, 1, 2, 3, 4…}
一个程序拥有的虚拟地址也是一个非负整数地址的有序集合,所以,我们可以称为虚拟地址空间。
相对虚拟地址空间,还有一个物理内存地址空间,物理内存地址空间的大小就是物理内存的容量 M 个字节,所以物理地址空间为:{0, 1, 2, 3…M-1}
主存中的每个字节都有:一个选自虚拟地址空间的虚拟地址和一个选自物理地址空间的物理地址。
ELF 文件最后留下的两个问题:
问题一:如果说32位系统的话,最大内存容量为4G,这个其实还好,但是64位系统的最大内存容量为256T,这个也太恐怖了,根本都没见过这么大的内存,那为什么可以支持这么大的内存地址呢?
- 解决方案:使用虚拟地址
问题二:所有的用户空间的内存被一个程序占据了吗?那其他程序需要内存的话,怎么办?
- 两个程序可以使用相同的虚拟地址,虚拟地址可以被随便使用,最终由操作系统做内存映射,转换为物理地址。
分页寻址
分段寻址的缺点:
-
外部碎片导致内存利用率降低,假如有60M内存的碎片,没有被使用,此时如果有一个程序需要50M内存,就会放不下
-
分段机制并不是一个高效管理内存的机制
分段寻址出现的原因:
-
当时在8086处理器引入分段的目的是为了解决 16位 CPU 寻址 20位内存的问题
32 位处理器,可以寻址 4G 内存
64 位处理器,可以寻址更大的内存
分页
-
虚拟内存分成若干个大小相同的虚拟页(Virtual Page, VP)
-
物理内存分成若干个大小相同的物理页(Physical Page, PP),也可以称为页帧(PF)
-
VP的大小 == PP的大小, PP的大小可以是:4KB、8KB、16KB…一般是 2 的幂
地址翻译 页表+MMU
如何确定某个虚拟页存放在哪一个物理页:
- 页表:页表维护了虚拟页到物理页的映射关系,页表中的每一项叫页表项 PTE
- 一个虚拟地址被分成两部分,其中低 X 位用来表示页内偏移 VPO(页大小=2^X),剩余的部分用来表示虚拟页号 VPN
- 在页表中查找虚拟页号 VPN 对应的物理页号 PPN,然后由物理页号 PPN + 页内偏移(VPO==PPO)得到对应的物理地址
分页寻址的地址翻译工作主要由硬件+软件配合实现:
- MMU:内存管理单元专用硬件,MMU单元负责虚拟地址到物理地址的翻译
- 页表由操作系统软件来维护
- 地址翻译工作主要是由MMU内存管理单元硬件到页表基址寄存器中查找页表后根据虚拟地址翻译成物理地址
需要注意的是MMU是一个位于CPU中的硬件单元,而页表是位于操作系统软件中的程序数据,它并不在CPU中。
多级页表 - 压缩页表占用内存的大小
多级页表如何寻址
通过每一级虚拟页表目录找到下一级页表项中的物理位置,最终找到对应的物理页号,再加上页内偏移得到物理地址(虚拟页内偏移等于物理页内偏移)
分页寻址总结
- 每个程序都有自己的虚拟页表
- 当 CPU 执行程序 2 的时候,CR3 寄存器会切换到对应程序 2 的虚拟页表的基地址,MMU 负责将程序代码段或数据段的虚拟地址通过多级页表翻译成对应的物理地址
- 不同的应用程序可以使用相同的虚拟地址,但是最终经过MMU翻译之后,会得到不同的物理页号PPN, 分配的是不同的物理地址