清华大学操作系统公开课(三)非连续内存分配

  为什么要采用非连续内存分配的方式?因为上一章讨论的连续内存分配算法(最先适配、最佳适配、最差适配)都有各种各样的问题。

  连续内存分配的缺点:

  • 分配给一个程序的物理内存是连续的
  • 内存利用率低
  • 有外碎片、内碎片的问题

  想要解决这些问题,可以考虑非连续内存分配。

  非连续内存分配的优点:

  • 一个程序的物理地址空间是非连续的
  • 更好的内存利用和管理
  • 允许共享代码和数据(共享库等)
  • 支持动态加载和动态链接

  当然,优点伴随而来的也有缺点,非连续内存分配的缺点在于虚拟地址和物理地址之间转换的开销大。建立虚拟地址和物理地址可以通过软件的方式也可以通过硬件的方式,如果单纯通过软件建立映射表的开销是非常大的,所以我们希望结合硬件的管理减少开销。

  两种硬件方案:

  • 分段
  • 分页

1.分段


分段定义

  分段机制想要根据应用程序执行的特点来对进程内存空间进行共享和分离。

 

  进程的段空间由多个段组成,包括主代码段、子模块代码段、公用库代码段、堆栈段、堆数据、初始化数据段、符号表等。段式存储管理的目的是更细粒度和灵活地分离与共享。

  我们可以看到,虽然程序的逻辑地址空间是连续的,但可以把它不同的段隔离开来,映射到不连续的物理地址空间上去。好处有很多,比如说可以便于共享(相互访问)和隔离(有些数据是读写的,有些数据是只读的)。

  前面提到分段需要硬件的支持,接下来介绍怎么通过硬件来支持分段寻址。

分段寻址方案

  逻辑地址主要包括两部分,段号和段内偏移。有两种实现方案,第一种是段号和段内偏移是分开的,这种是段寄存器+地址寄存器的寻址方式,X86就是这种方式寻址;第二种是段和段内偏移合成一个单地址的寻址方式。

  段的寻址过程如上图所示。从左上角开始程序交给CPU运行,CPU拿着逻辑地址的段号到段表中寻找对应的物理地址。段表里面存着逻辑地址到物理地址的映射,段表里面有两个重要信息:段的起始地址和段的长度。CPU将段号的实际物理起始地址加上前面逻辑地址的偏移量得到要访问数据的地址,这时CPU会检查内存的访问是否会出现异常,若非法操作则拒绝请求,否则返回对应地址的数据。

  在段寻址的过程中段表是关键,操作系统要在正式的寻址开始前建立好段表。

2.分页


  前面介绍了分段机制,分段机制在现有的CPU硬件环境中用的是比较少的,现在绝大部分CPU主要采取的是分页机制。分页机制也需要依靠页号和页偏移量来寻址,那与分段的区别在于,分段机制每个段的尺寸是可变的,而在分页机制中,每个页或者叫页帧的尺寸是固定不变的。

  分页机制要划分物理内存至固定大小的帧(frame),大小是2的幂(e.g.,512,4096,8192);划分逻辑内存至相同大小的页(page),大小是2的幂(e.g.,512,4096,8192);除此之外要建立逻辑内存的页(page)到物理内存的帧(frame)的映射。

  建立方案 转换逻辑地址到物理地址:

  •     页表
  •     MMU/TLB

物理帧的寻址方式

 

  分页也是通过页帧号和帧内偏移计算出实际的物理地址(帧号是通过逻辑地址页号+查表得到?),每个帧的大小为2^s个字节,所以根据上图的物理地址计算公式可以得到实际物理地址。

  在上面计算的实例中,我们可以看看怎么计算地址。假设我们有一个16-bit(2^16 bit)的地址空间,每一个页帧的大小为9-bit(2^9 bit),可以用公式计算出来。

逻辑页的寻址方式

  逻辑页的寻址方式和物理帧的寻址方式类似。

  逻辑页到物理帧的完整映射流程可由下图所示:

  从左上角开始程序交给CPU运行,CPU拿着逻辑地址的页号到页表中寻找对应的帧号,页表查找要知道从哪里开始找,这就用到了页表基址。知道帧号以后帧号+帧内偏移找到对应的物理地址。页表依旧是由操作系统在分页机制初始化时候就建好。

  同时要知道,逻辑地址空间大小不一定等于物理地址空间大小,物理地址空间可能比逻辑小,不是所有的页都有对应的帧,这就要考虑虚拟内存机制;逻辑地址中的页号是连续的,物理地址中的帧号是不连续的。

 

3.页表


页表概述

  查询页表是寻址中比较重要的环节,输入页表号,得到页表项,页表项除了对应帧号以外,还会得到页表项标志的信息。

  这些标志有一些特殊用途,比如说可以表示该页表项是否是合法页表项,即对应的物理空间是否存在。前面提到逻辑空间可能大于物理空间,如果对应的bit是0就说明该页表项逻辑空间对应的物理空间可能就不存在了。

  图中可以看到地址转换例子,逻辑地址大小是16-bit(64 KB) 而物理内存大小是32KB,看看(4,0)和(3,1023)是如何寻址的。

  (4,0) : 首先CPU找到逻辑地址 ===>查页表第四项 ===> 帧号为0 ===> 但要注意存在位标志位为0  ===> 表明该页对应的帧在物理内存中不存在,没有这种映射关系 ===> 产生内存访问异常。

  (3,1023):首先CPU找到逻辑地址 ===>查页表第三项  ===> 存在位为1 ===>对应页帧号为4  ,偏移量为1023 ===> 计算出物理地址。

页表机制的性能问题

  分页机制看起来比较完善,但是仔细想想性能还是存在问题。

  页表也有可能变的很大:比如一个64位机器如果每页1024字节,那么一个页表的大小有多大?2^64/2^10 = 2^54 (个),一般计算机没有这么大空间,甚至没法存下一个页表;而且进程访问空间需要隔离,每一个进程就要维护一个页表,n个进程就要维护n个页表;如果这样的设计CPU肯定放不下,只能放在内存里面,我们希望寻址尽量快,但问题在于访问一个物理地址内存单元需要两次内存访问,一次用于获取页表项,一次用于访问数据,这样开销是很大的。

  如何解决?对于计算机而言,一般解决这种时间/空间问题有两种办法:

  • 缓存:把最常用的数据放到离CPU近的地方
  • 间接访问:通过索引(多级页表机制)把很大的空间拆成一个较小的空间。

TLB

先说时间优化。时间靠缓存解决,缓存靠TLB实现,TLB是CPU的MMU模块里的一个缓存(cache),缓存页表的内容。TLB速度快但容量有限,数据以key/value键值对的方式存储,把经常用到的一些页表项放在TLB中,CPU就不用去页表查找了,先查TLB,如果找不到(TLB MISS)再去内存页表里查找。

  TLB缺失的情况会不会很多呢?不会很多,一般32位系统一个页是4K,一般访问都会集中在这4K中,不会很容易缺页。那么写程序的时候也要注意程序访问的局部性,把访问集中在一定区域内,可以有效减少TLB MISS。

  还有就是注意,TLB MISS后把页表项从页表里取出来再存到CPU TLB中,这个过程是由操作系统完成还是由硬件完成,这是和操作系统特征有关的,X86完全由硬件完成,其他操作系统也有完全靠软件实现的情况。

多级页表

  刚说了依照TLB优化时间,再说依据多级页表优化空间。

    我们可以看到二级页表寻址的流程图如上,和刚才不一样的是把逻辑地址的页号分成了p1、p2两部分,先利用p1到第一级页表中寻找到对应第二级页表的起始地址,再用对应第二级页表的起始地址加上p2找到帧号,加上页偏移量得到物理地址。这种将页表分级的做法有效减少了页表的空间。比如p1列表项中一项的存在位为0,那么对应二级页表整个就不用存储,对比单一页表,即使不存在,对应页表还是要保留,这样就省下了空间。

  通过二级页表还可以推广到多级页表,形成类似树的结构,级数越多需要额外访问的次数就越多,但是空间就越小,这就是一种以时间换空间。

3.反向页表


  其实前面的非连续内存分配都有一个特点,页表的大小都和逻辑空间的大小是有关的,也就是随着逻辑空间的变大,页表也在变大。那么有没有一种分配方式,页表的大小与逻辑空间大小没那么大关系?这其实说的就是反向页表想法。

  前面讲的页表都是以逻辑页的页号作为index来索引一个大数组,那么我们能否以物理页号作为index来查找逻辑页号呢?

  接下来介绍通过反置页表的查找流程,CPU此时是凭借帧号和帧偏移量去寻找页号。这样页表与物理内存空间大小有关,不会随着逻辑空间改变,有效限制了页寄存器的数量。但很明显的问题在于,我们分页的目的在于CPU根据页号来查找帧号,那么建立这么一个数据结构后,我们只有以帧号为index对页号的单向映射,我们如何通过页号找到帧号?

  在解决之前先来看看页寄存器这种机制的好处。

  通过图中例子可以看出16MB物理内存的计算机,假如页面大小为4KB,那就有4K个页帧数量,页寄存器使用的空间为32K,只占用整个内存0.2%,占用空间很小。但存在的问题就是怎么建立页号到帧号的映射关系。

  那我们需要调整一个页寄存器的结构解决映射的问题。

基于hash的查找方案

  哈希是很简单的一种数学计算的方法,输入一个页号,得到一个帧号。这里注意两点:1.哈希函数的计算可以用硬件加速,提高效率。2.为了提高效率,可以给哈希函数再加一个参数,加入当前运行进程的PID(进程ID)与页号合成一个很好的输入。

  这样的方式可能出现的问题:

  •     哈希碰撞:尽管输入加入了PID有缓解,但同一个哈希值还是有可能对应多个帧号,需要分辨哪一个是需要的。
  •     时间效率:还是要到内存中访问数据,需要TLB这样的机制减少对内存的访问。

  目前来说,反向页表的机制只有在某些高端计算机中才会设计存在。  

 

 

 

 

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值