操作系统导论 | 第 16 章笔记

76 阅读3分钟

第16章 分段

关键问题:怎样支持大地址空间,同时栈和堆之间可能有大量空闲空间?

16.1 分段:泛化的基址/界限

image.png

image.png

16.2 我们引用哪个段

硬件在地址转换时使用段寄存器,它如何知道段内的偏移量,以及地址引用了哪个段?

一种常见的方式,有时称为显式 (explicit) 方式,就是用虚拟地址的开头几位来标识不同的段。

image.png

在之前的例子中,有3个段,因此需要2位来标识,剩下的12位是段内偏移。

硬件还有其他方法来决定特定地址在哪个段。在隐式 (implicit) 方式中,硬件通过地址产生的方式来确定段。

16.3 栈怎么办

在表 16.1 中,栈被重 定位到物理地址 28KB。但有一点关键区别,它反向增长。在物理内存中,它始于 28KB,增长回到 26KB,相应虚拟地址从 16KB 到 14KB。地址转换必须有所不同。

image.png

16.4 支持共享

具体来说,要节省内存,有时候在地址空间之间共享某些内存段是有用的。

为支持共享,需要一些额外的硬件支持,这就是保护位基本为每个段增加了几个位,标识程序是否能够读写该段,或执行其中的代码。通过将代码段标记为只读,同样的代码可以被多个进程共享,而不用担心破坏隔离。虽然每个进程都认为自己独占这块内存,但实际上是操作系统秘密地共享了内存,进程不能修改这些内存,所以假象得以保持。

image.png

有了保护位,前面描述的硬件算法也必须改变。除了检查虚拟地址是否越界,硬件还需要检查特定访问是否允许。

16.5 细粒度与粗粒度的分段

到目前为止,我们的例子大多针对只有很少的几个段的系统(即代码、栈、堆)。我们 可以认为这种分段是粗粒度的(coarse-grained),因为它将地址空间分成较大的、粗粒度的块。但是,一些早期系统(如 Multics[CV65, DD68])更灵活,允许将地址空间划分为大量 较小的段,这被称为细粒度(fine-grained)分段。

16.6 操作系统支持

现在你应该大致了解了分段的基本原理。系统运行时,地址空间中的不同段被重定位 到物理内存中。与我们之前介绍的整个地址空间只有一个基址/界限寄存器对的方式相比, 大量节省了物理内存。具体来说,栈和堆之间没有使用的区域就不需要再分配物理内存, 让我们能将更多地址空间放进物理内存。

然而,分段也带来了一些新的问题:

  1. 操作系统在上下文切换时应该做什么? 答:各个段寄存器中的内容必须保存和恢复。

  2. 如何管理物理内存的空闲空间?

    一般会遇到的问题是,物理内存很快充满了许多空闲空间的小洞,因而很难分配给新的段,或扩大已有的段。这种问题被称为外部碎片 (external fragmentation)

    解决方案1:紧凑物理内存,重新安排原有的段。

    image.png

    解决方案2:利用空闲列表管理算法,试图保留大的内存块用于分配。相关的算法可能有成百上千种。

PS:如果有一千个解决方案,就没有特别好的。

16.7 小结

分段的优点与缺点。

“开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 20 天,点击查看活动详情