📂 操作系统 - Operating System / Chapter II 虚拟化 / Section 2 内存虚拟化 / 2-2 分段与分页

机制:分段

2026-05-11
#OS
  • 分段:泛化的基址/界限

    • 分段(Segment)的概念:
      • 在MMU中引入不止一对基址和界限寄存器,而是给地址空间内的每个逻辑段都分配一对
      • 一个是指地址空间中一片连续定长的区域
      • 在一个典型的地址空间中存在三个逻辑不同的段:代码,分段的机制让操作系统能够将不同的段分配到不同的物理内存区域
      • 这会仅让已被使用的内存能在物理内存内分得空间,因此可以容纳巨大的地址空间,其中包含大量未使用的地址空间(又称“稀疏地址空间(Sparse address spaces)”)
      • 为了表示反向增长的栈段,硬件还会记录一个表示“是否正向增长”的值,用于区分栈段与堆、代码段
    • 段错误(Segmentation fault)
      • 段错误发生于程序试图访问非法的地址,或不允许被如此操作的地址(不属于这个程序的任何段的地址)
  • 段类型的标识

    • 显示(Explicit)方式
      • 使用虚拟地址的开头几位来表示访问的是代码段、堆段或栈段
    • 隐式(Implicit)方式
      • 硬件通过地址产生的方式来判断应当访问哪个段,例如:
        • 如果地址由程序计数器产生(指令获取),那么它在代码段
        • 如果是基于栈或基址指针,则在栈段
        • 其余情况则是在堆段
  • 共享

    • 有一些内存段是可以在不同进程之间共享(Share) 的,例如代码段
    • 共享内存需要一些额外的硬件支持,也就是保护位(Protection bit)。保护位会给段增加几个位,用于标识进程能否读/写该段,或执行其中的代码
    • 如果进程试图对某个段做不被保护位允许的操作,则也会引发段错误
    • 通过将代码段标识为只读,这样同一块代码段就可以被多个进程共享,而不用担心破坏隔离
      • 每个进程都认为自己独占这块段,但实际上是操作系统秘密的将这一块代码段共享给了它们,地址空间的假象仍然可以维持
  • 粗粒度与细粒度

    • 将地址空间分的块越大,就代表这种分段方式越接近粗粒度的,反之则是细粒度
    • 支持分许多段需要进一步的硬件支持,并在内存中保存段表(Segment table),这种段表可以支持非常多的分段,甚至是将代码段和数据段划分为许多不同的部分,更加高效地利用内存
  • 分段存在的问题

    • 操作系统在切换上下文时需要将各个段寄存器的内容都给正确保存与恢复
    • 新的地址空间被创建时,操作系统需要在物理内存中给这个进程分配三个段,随着分配的段越来越多,内存中就会出现很多很多的“小空洞”,这些洞就是外部碎片(External fragmentation),它们太小了,以至于没法被分配新的段,造成内存浪费
      • 解决办法之一是紧凑(Compact)物理内存,重新安排原有的段
        • 步骤
          1. 操作系统终止运行中的进程
          2. 将它们的数据复制到连续的内存区域,改变他们的段寄存器中的值,指向新的物理地址
          3. 从而得到比较大的连续空闲空间
        • 但内存紧凑的成本很高,因为拷贝段是连续密集的,一般会占用大量的处理器时间
      • 另一种办法是使用空闲列表管理算法
        • 这类算法会试图保留大的内存块进行分配
        • 这些算法包括最优匹配(Best-fit)、最坏匹配(Worst-fit)、首次匹配(First-fit)等