内存管理(二)——内存分段

前言

上一篇讲了连续型分配,这篇开始介绍非连续型分配,也是现代操作系统所使用的内存分配方式。首先从内存分段开始。

分段管理

在内存分段管理中,程序是由若干个逻辑分段组成的,如可由代码分段、数据分段、栈段、堆段组成。不同的段是有不同的属性的,所以就用分段(Segmentation)的形式把这些段分离出来。

分段机制下的虚拟地址由两部分组成,段选择符段内偏移量

  • 段选择符就保存在段寄存器里面。段表里面保存的是段描述符,包括这个段基地址、段界限和特权等级等。
  • 虚拟地址中的段内偏移量应该位于 0 和段界限之间,如果段内偏移量是合法的,就将段基地址加上段内偏移量得到物理内存地址。

内存管理(二)——内存分段_第1张图片

段选择符

在这里插入图片描述

段选择符包括 3 个字段的内容:

  • 请求特权级 RPL([0:1]):任务中的每一个段都有一个特定的级别。当一个程序试图访问某一个段时,就将该程序所拥有的特权级与要访问的特权级进行比较,以决定能否访问该段。系统约定,CPU 只能访问同一特权级或较低特权级的段。
  • 表指引标志 TI([2]):TI = 0 ,表示描述符在 GDT 中;TI = 1,表示描述符在 LDT 中。
  • 索引值:给出了描述符在 GDT 或 LDT 中的索引项号。

段描述符

进程的逻辑地址空间分为两部分,第一部为进程私有,该部分信息存储在局部描述符表(Local Descriptor Table,LDT),第二部分为所有进程所共享,该部分信息存储在全局描述符表(Global Descriptor Table,GDT)。

GDT 和 LDT 都是存储在内存当中的,但是 CPU 中有 GDTR 和 LDTR 两种寄存器,用来存储两者的入口位置。一个处理器只有一张 GDT,而每个任务都有一张 LDT,LDT 是嵌套在 GDT 中的。GDTR 中存放的是 GDT 在内存中的基地址和其表长界限(描述符)。LDTR 的内容是一个段选择子,用于记录 LDT 的起始位置。

内存管理(二)——内存分段_第2张图片

访问 GDT
  1. 先从 GDTR 中获得 GDT 基址。
  2. 然后在 GDT 中以段选择器高 13 位位置索引值得到段描述符。
  3. 段描述符符包含段的基址、限长、优先级等各种属性,这就得到了段的起始地址(基址),再以基址加上偏移地址就能得到最后的线性地址。
访问 LDT
  1. 先从 GDTR 中获得 GDT 基址。
  2. 再从 LDTR 中获取 LDT 所在段的位置索引(LDTR 高 13 位)。
  3. 以这个位置索引在 GDT 中得到 LDT 段描述符从而得到 LDT 段基址。
  4. 用段选择器高 13 位位置索引值从 LDT 段中得到段描述符。
  5. 段描述符符包含段的基址、限长、优先级等各种属性,这就得到了段的起始地址(基址),再以基址加上偏移地址就能得到最后的线性地址。

优点:

  • 每个逻辑单元可以单独占用一个虚拟地址空间。
  • 按逻辑关系划分,方便共享和保护。
  • 对于空间稀疏的程序来说,分段管理将节省大量的空间。

缺点:

  • 存在外部内存碎片问题。可以通过改变段的大小消除内部碎片,但是段换入换出时仍然会产生外部碎片。

可以用过内存交换的方式解决外部内存碎片的问题,但是会产生性能瓶颈。因为硬盘的访问速度要比内存慢太多了,每一次内存交换,都需要把一大段连续的内存数据写到硬盘上。

交换技术

Swapping,以进程为交换的单位,需要把进程的整个地址空间换入换出,增加了处理器的开销。

  • 可将暂时不能运行的程序送到外存 ,从而获得空闲内存空间;
  • 操作系统把一个进程的整个地址空间的内存保存到外存中(换出 swap out),而将外存中的某个进程的地址空间读入到内存中(换入 swap in)。换入换出内容的大小为整个程序的地址空间。

缺点:

  • 以整个进程为单位进行交换,交换的开销很大。

总结

内存分段是将程序按照逻辑分成多个不同的段,再给每个段分配各自的物理空间,在使用逻辑地址时,通过段表映射到相应的物理段进行使用。其中,段表分为全局描述表和局部描述表,再通过寄存器来存储表的开始地址。

因为各个分段的大小不同,所以在换入换出的过程中会产生外部碎片,可以通过交换的方式清除这些外部碎片,但是由于是以整个进程为单位进行交换,所以开销非常大。

你可能感兴趣的:(操作系统,操作系统,内存管理,内存分段)