📂 操作系统 - Operating System / Chapter II 虚拟化 / Section 2 内存虚拟化 / 2-1 虚拟内存

机制:地址转换

2026-05-10
#OS
  • 基于硬件的地址转换(Hardware-based Address Translation)

    • 简称为“地址转换(Address Translation)
    • 当应用程序对内存进行访问时,硬件会对这个访问指令进行处理,将指令提供的虚拟地址转换为数据实际存储在的物理地址;也就是将应用的内存引用重定位到实际的内存位置
    • OS必须参与管理内存,记录被占用的和空闲的内存位置,在需要的时候介入以保证对内存的控制
  • 介入(Interposition)技术

    • “介入”指在客户端与服务端之间插入一层机制,来完善或扩展API的功能
    • 定义良好的API都应当提供介入机制,以扩展API的功能
    • 介入的特点是透明(Transparency),介入时不需要改动API的客户端
    • 在内存虚拟化方面,介入的一个例子就是硬件介入到应用程序的内存访问
  • 一些假设

    与CPU虚拟化相同,我们需要一些假设来帮助我们思考问题
    • 假设1:地址空间并不大,大小小于物理内存的大小
    • 假设2:地址空间必须连续地存储在物理内存中
    • 假设3:每个地址空间的大小一致
  • 地址转换的实现

    • 地址转换的思想

      • 例:假设有一个应用程序
        • 对于这个应用程序来说,它占有0KB16KB的内存,0KB2KB存储程序代码,2KB向高位存储堆区,16KB向低位存储栈区,堆区与栈区中间可能有不少内存待分配给堆区或栈区
        • 实际上,这个应用程序可能被分配到的物理内存是这样的:32KB~34KB存储程序代码,34KB向高位存储堆区,48KB向低位存储栈区
    • 动态重定位(基于硬件)

      • 在20世纪50年代出现了一个思想,叫做基址加界限机制(Base and Bound),也称为动态重定位(Dynamic Relocation)
      • 动态重定位的内容
        • 每个CPU的内存管理单元(MMU, Memory Management Unit) 需要两个硬件寄存器:基址寄存器和界限寄存器(限制(Limit)寄存器),这组寄存器能够存在于物理内存的任何位置,能保证进程只能访问自己的地址空间
        • 在上面的例子中:由于地址空间的起始位置在物理内存中是32KB的位置,所以基址寄存器就被设置为32KB;因为这个应用程序占用16KB的内存,所以界限寄存器被设置为16KB
        • 由于这种机制的存在,OS甚至可以在进程开始后将它的地址空间迁移到物理内存中的其他位置
      • 动态重定位的机制
        • 当应用程序发起内存访问时,如果程序想要访问的地址(虚拟地址)负数或者大于界限寄存器(16KB),那么CPU会触发异常,OS会介入然后处理异常(很可能会终止进程)
        • 如果虚拟地址的检查没有问题,那么CPU就会根据基址寄存器的内容找到最终应当访问的物理内存
      • 曾经出现过的静态重定位
        • 纯软件操控虚拟内存到物理内存的映射,被称为静态重定位(Static Relocation)
        • 这种方式使用了一种叫做“加载程序(Loader)”的软件,它将会将程序的指令地址偏移到正确的物理地址
        • 这种方法不提供访问保护,且地址空间在确定后很难迁移到其他位置
        • 静态重定位常在编译后完成,无法适应多道程序设计(缺乏隔离)
  • 空闲列表

    • 空闲列表(Free List)是一种数据结构,它是一个用于记录当前没有使用的物理内存的范围的列表
  • 由于虚拟内存的出现,操作系统需要做的事情

    • 进程被创建时,OS会检索空闲列表,在物理内存中找到存放它的地址空间的地方
    • 进程终止时,OS必须回收它的所有内存更新空闲列表,并根据需要清除相关数据结构
    • 在上下文切换时,OS必须将基址寄存器和界限寄存器内存储的内容存储到上下文切换所用的数据结构中,如进程结构(Process Structure)或进程控制块(PCB, Process Control Block)。在恢复一个进程时也必须给这组寄存器赋予正确的值
    • 进程停止时,OS可以更改这个进程的地址空间的物理位置。具体做法是让进程停止,然后将地址空间拷贝到新位置,最后更新基址寄存器(在进程结构中)指向新位置
    • OS必须提供异常处理程序。当程序访问内存出问题时,CPU会触发异常,然后OS会处理这个异常
    • 在大多数情况下,与受限直接执行(LDE, Limited Direct Execution) 一样,OS会任凭进程在CPU上运行,等到需要OS介入时OS才会介入
  • 动态重定位存在的问题

    • 如果一个应用程序的栈区和堆区不是很大,那么会导致栈区和堆区之间的很大一片内存被浪费。这些浪费被称为“内部碎片(Internal Fragmentation)”,指的是“已经分配的内存单元内部的未使用的空间”。由此,我们需要更复杂的机制来更好地利用内存,比如说放宽假设2,得到分段(Segmentation) 的概念