《操作系统导论》第二部分 内存虚拟化 P3 分段

C4 分段

目前为止,一直假设将所有进程的地址空间完整的加载到物理内存中,利用基址和界限寄存器,操作系统很容易将不同进程重定位到不同的物理内存区域,但是在堆和栈之间,有一大块“空闲”空间,即内部碎片

因此,简单地通过基址寄存器和界限寄存器实现的虚拟内存很浪费物理内存,如果剩余的物理内存无法提供连续区域来放置完整的地址空间,那么进程便无法运行,因此需要更高级的地址转换机制

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

为了避免内部碎片和提高物理内存的利用率,分段应运而生

分段:在内存管理单元(MMU)中引进不止一对基址,界限寄存器,而是给地址空间内的每个逻辑段一对基址,界限寄存器,典型的地址空间有3个逻辑段,代码段,堆段,栈段

分段的机制使得操作系统将不同的段放到不同的物理内存区域,从而避免了内部碎片,提高了物理内存利用率

一个分段例子:
通过给每一个逻辑段一对基址,界限寄存器,将每个逻辑段重定位到物理内存中,每个逻辑段的基址寄存器记录它被加载到物理内存的起始位置,界限寄存器记录该逻辑段的大小

在这里插入图片描述
假设引用虚拟地址100(在代码段中),代码段基址为32kb,虚拟地址100在代码段地址空间中的偏移量为100-0,则物理地址为32kb+100=32868,然后检查该地址是否在界限内(100<2kb),通过后发起对物理地址32868的引用

假设引用虚拟地址4200(在堆中),堆基址为34kb,虚拟地址4200在堆地址空间中的偏移量为4200-4kb=104,则物理地址为34kb+104=34920,然后检查该地址是否在界限内(104<2kb),通过后发起对物理地址34920的引用

如果试图访问非法的地址,硬件会发现越界,因此trap进内核,操作系统终止进程

4.2 应该引用哪个段: 虚拟地址前两位指明哪个逻辑段

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

(1) 显式方式

一种常见的方式,称为显式方式,即用虚拟地址的开头几位来标识不同的段,VAX/VMS系统使用了这种技术,之前的示例中,分了3个逻辑段,因此用14位虚拟地址表示时,虚拟地址前两位标识是哪个段,后12位表示该虚拟地址在对应段中的偏移量

在这里插入图片描述
上述14位虚拟地址,用前两位01表示是代码段,告知地址转换时使用代码段的基址,界限寄存器,后12位是该虚拟地址在代码段中的偏移量,偏移量与基址寄存器相加就得到了最终的物理地址

偏移量也简化了对界限的判断,只要检查偏移量是否小于界限,大于界限的被认为是非法地址

(2) 隐式方式

硬件通过地址产生的方式来确定段,例如,如果地址由程序计数器产生,则地址在代码段,如果基于栈或基址指针,则一定在栈段,其它地址在堆段

4.3 栈怎么处理:虚拟地址增加是否反向增长位

虽然分段可以避免内部碎片,通过虚拟地址中用位标记使用哪对基址,界限寄存器,但是注意栈的结构,它反向增长

栈在虚拟内存中从16kb增长到14kb,相应的物理地址从28kb增长到26kb,地址转换必须有所不同

在这里插入图片描述
除了基址,界限寄存器外,硬件还需要知道段的增长方向(用虚拟地址中的某一位区分,如1代表正向增长,0代表反向增长)

4.4 支持共享:虚拟地址增加访问权限位

随着分段机制的不断改进,系统设计人员意识到,通过再多一点的硬件支持,就可以实现新的功能,从而提升更多的效率,,具体来说,要节省内存,有时在地址空间之间共享代码段是很有用的

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

在这里插入图片描述
有了保护位,除了检查虚拟地址是否越界外,硬件还要检查特定访问是否允许,如果用户进程试图写入只读段,或从不可执行段执行指令,硬件会触发异常,让操作系统处理

4.5 细粒度和粗粒度的分段

到目前为止,只针对只有很少的几个段的系统(代码段,堆段,栈段),可以认为这种分段是粗粒度分段,因为它将地址空间分为较大的,粗粒度的块

但一些早期系统更灵活,它们允许将地址空间划分为大量较小的段,这被称为细粒度分段,支持许多段需要进一步的硬件支持,并在内存中保留某种段表,这种段表通常支持创建非常多的段,因此系统使用段的方式,可以更加灵活,通过更细粒度的段,操作系统可以更好地了解哪些段在使用哪些段没有,从而更高效利用内存

4.6 操作系统为分段提供更多功能

分段的基本原理:系统运行时,地址空间中的不同逻辑段被重定位到物理内存中,避免加载栈和堆之间没有使用的区域,提高了物理内存的利用效率

但分段也为操作系统带来了新的问题:

(1) 保存和恢复各进程的逻辑段的寄存器中的值

各个段基址,界限寄存器的值是不一样的,操作系统在上下文切换进程时,必须保证每个进程的各个段的寄存器内容必须保存,且切换回来时,要正确恢复

(2) 减小外部碎片,管理物理内存的空闲空间

新的地址空间被创建时,操作系统需要在物理内存中为它的段找到合适的空间,每个进程都有一些段,每个段的大小可能不相同,一般会遇到的问题是:物理内存很快充满了许多小片的空闲空间,因而很难分配给新的段,或扩大已有的段,这种问题称为外部碎片

如下图的物理内存,当前有一个进程需要分配20kb的段,当前物理内存有24kb空闲但并不连续,因此,操作系统无法满足这次请求

在这里插入图片描述
该问题的一种解决方案是紧凑物理内存,即重新安排物理内存中已有的段,如操作系统先终止运行的进程,将它们的数据复制到连续的内存区域中,改变它们的段寄存器的值,指向新的物理地址,从而得到足够大的连续的物理内存,但是紧凑物理内存成本很高,需要占用大量的处理器时间
在这里插入图片描述

更为简单高效的是利用空闲列表管理算法,试图保留大的内存块用于分配,相关的算法可能有上千种,包括最优匹配,最坏匹配,首次匹配,伙伴算法等,但无论算法多么精妙,都无法完全消除外部碎片,只能试图减小

4.7 小结

分段实现了更高效的虚拟内存,不只是动态重定位,通过避免地址空间的逻辑段之间的大量潜在的内存浪费,分段能更好的支持稀疏地址空间,它还很快,因为分段的算法很容易,适合硬件完成,地址转换的开销极小,分段还可以代码共享,进一步提高物理内存利用率

但是不同的地址空间有不同的逻辑段,其长度是不确定的,虽然分段避免了内部碎片,但是接踵而来的是外部碎片的问题,由于段的大小不同,空闲内存被割裂成各种奇怪的大小,因此满足后续的内存分配会很困难,需要更好的算法减少外部碎片

而且分段还是不足以支持更一般化的稀疏地址空间,如有一个很大但是稀疏的堆,分段还是会将整个堆段完整加载到内存中,在某些情况下,分段的效果还是差强人意

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值