《操作系统概念精要》之内存篇(二)-分段-分页

分段 基本概念

《操作系统概念精要》之内存篇(二)-分段-分页
在编写代码的时候,程序员认为它是由主程序加上一组方法,过程或者函数的集合。他还包括这种数据结构:对象,数组,堆栈,变量。每个模块或者数据元素通过名字来引用。而不关心具体的内存位置。
分段就是支持这种用户视图的内存管理方法。逻辑地址空间是由一组段构成。每个段都有名称和长度,比如,代码段,数据段,堆栈,堆等等。
地址指定了段名称和段内偏移。所以段一般是由两个量来进行表示:
<段号, 偏移>

通常,在编译用户程序的时候,编译器会自动生成:

  • 代码
  • 全局变量
  • 程序库

分段的硬件实现

虽然用户可以实现通过二维地址来引用程序内的对象,但是实际物理内存还是一维的字节数组。因此需要我们需要定义一个映射方法,把二维地址转换为一维地址。

这个地址是通过段表来实现的。段表的每个条目都有一个段基地址和段界限。段基地址包含该段在内存中的开始物理地址,而界限地址指定该段的长度。
《操作系统概念精要》之内存篇(二)-分段-分页
从图中,我们可以看到段表和每个段的分布情况。

再看看分段的硬件实现,每个逻辑地址都有两个部分来实现,段号s和偏移d。 当我们从CPU的指令中得到一个地址时,它有段号和偏移d,段号首先去段表中进行索引,获取到段基(base)地址,然后加上偏移d,然后和 界限地址进行比较,得到最终的物理内存地址。(这里段表上两个元素实际上是基地址寄存器和界限寄存器组成的结构体数组)。
《操作系统概念精要》之内存篇(二)-分段-分页

分页

分段允许进程的物理地址空间可以分为多个段,从而地址可以是非连续的。然而分段还是避免不了有外部碎片的情况,因为在给每个段分配内存的时候,各个段的大小是不一样的。从而让整块物理内存还是会有缝隙。分页避免了这种情况。

基本概念
实现分页的最基本方法涉及到将物理内存分为固定大小的块,称为帧或者页帧(frame,从英文名可以看出来这是个框架);而将逻辑内存也分为同意大小的块,叫做页或者页面(page, 从英文名可以看出来这是一页纸)。

当需要执行一个进程时,它的页从文件系统或者磁盘中加载到内存的可用页帧中。磁盘也被划分为固定大小的,它与单个内存(frame)或者分为多个内存帧的大小一样。

分页的硬件支持
分页的硬件支持和分段类似,由CPU解码后的指令地址(逻辑地址)分为两个部分:页码(page number)和页偏移(page offset)。
页码作为页的索引。页表包含每页所有物理内存的基地址。这个基地址与页偏移的组合形成了物理内存地址。
《操作系统概念精要》之内存篇(二)-分段-分页
再看看页表的结构(注意这里的地址用的是帧码,也就是frame的页号,而不是字节)。
《操作系统概念精要》之内存篇(二)-分段-分页
我们通过上面的学习,应该可以看到,分页本身是一种动态的重定向。每个逻辑地址由分页硬件绑定某一个物理地址。采用分页类似于一个基地址寄存器,每个基址代表一个一个内存帧。

当系统进程需要执行时,它将检验该进程的大小,进程的每页都需要一帧。因此一个进程需要n页,那么内存中至少应该有n帧。如果有,那么可分配给新进程。进程的第一页装入一个已分配的帧,帧码会在装入后写到进程的页表中,下一页分配给另一帧,然后帧码也会写到进程的页表中。
《操作系统概念精要》之内存篇(二)-分段-分页
有了分页,程序员就可以将内存看做一整块来处理。内存的分配和管理交给操作系统。他可以认为他的程序在逻辑上是连续的,但是实际上,物理内存中他们是分布在不同的帧上的。在操作系统管理内存的分配时:它需要知道哪些帧已经分配,哪些帧空着,总共有多少帧。这些都在内核的叫做帧表 (frame table)的数据结构中。在帧表中每个条目对应一个帧,以表示该帧是空闲还是已占用;如果占用,是被那个进程占用。

分页的效率讨论

  • 页表具体的结构是怎样的?
    每个操作系统都有自己保存页表的方法。有的系统为每个进程分配一个页表然后通过指针保存在PCB中。当启动一个进程的时候,他应该首先加载一个用户寄存器,并通过保存的用户页表来定义正确的硬件页表值。
  • 页表的硬件实现时怎样的?
    页表的硬件实现有很多种,但是最简单的方法是通过一组专用的寄存器来实现。这些寄存器应用高速逻辑电路来构成,以高效的进行分页地址的转换。由于每次访问内存都要经过分页映射,因此效率是一个重要的考虑因素。CPU分派器在加载其他寄存器时,当然也需要加载这些寄存器,当然,这些页表寄存器的加载指令也是特权的。
  • 用寄存器来实现页表的问题?
    如果页表比较小的时候,用页表寄存器时效率是很高的。但是现在的计算机基本都允许页表很大,对这些机器,采用寄存器就不行了。因此,页表需要放在内存中,并将页表基地址寄存器(PTBR)指向页表,改变页表只需要操作这一个寄存器就可以了
  • 采用页表基地址寄存器的效率?
    采用这种方法的问题是访问用户内存位置的所需时间,如果需要访问位置i, 那么应该首先利用 PTBR的值,再加上i的页码,作为偏移,来查找页表。这一任务需要内存访问。 根据所得的帧码,再加上页偏移,就得到了真是的物理地址。接着就可以访问内存内的所需位置。采用这种方案,访问一个字节需要两次内存访问(一次是页表,一次是字节)。这样内存的访问效率就减半了。

因为效率问题,我们的解决方案是采用专用的,小的,查找快速的高速硬件缓冲,它称为转换表缓冲区(TLB)。它是一个关键的高速内存。
-TLB的工作原理
TLB条目由两部分组成:键和值。当关联内存根据给定值查找时,它会同时与所有的键进行比较。那么就得到相应的值。搜索的特别快。现代TLB的查找硬件是指令流的一部分,基本不会考虑性能代价。
TLB只包含了少量的页表条目。当CPU产生一个逻辑地址后,它的页码就送到TLB,如果他能找到这个页码,它的帧码也就立即可用,可用于访问内存。如果页码不在TLB中,那么就需要访问页表(访问内存)。取决于CPU,这可能由硬件自动处理或者通过系统的中断来处理。当得到帧码后,就可以用它来访问内存,同时还会把页码和页帧加到TLB中。
《操作系统概念精要》之内存篇(二)-分段-分页
有的TLB在每个TLB条目中还保存地址空间标识符,他唯一标识每个进程,并为进程提供地址空间的保护。
TLB是一个硬件功能,我们不需要关心,但是了解他的功能和特性,有利于我们在开发时,进行系统的优化。

分页的安全讨论
分页环境下的内存保护是通过与每个帧关联的保护位来实现的,通常这些 保护位会保存在页表中。

用一个位可以定义一个页是可读可写或只可读。每次内存引用都要通过页表,来查找正确的帧码。在计算物理地址的同时,还可以通过检查保护位来保护系统对内存的正确操作。

还有一个位通常与页表中的每一条项目相关联:有效-无效位。
当该位是有效位时,该值表示相关的页在进程的逻辑空间中内,因此它是合法的页。
当改为为无效位时,表示相关的页不在进程的逻辑地址空间内。
通过有效–无效位,非法地址会被捕捉,然后操作对该地址进行允许和不允许对某页的访问。
《操作系统概念精要》之内存篇(二)-分段-分页
对于上图:14位地址空间 (016383)的系统,假设有一个程序,它的有效地址空间是010468。如果页的大小是2k,那么他会有5个页表。然而,如果试图产生页表 6和页表7,那么操作系统就会根据有效-无效位的捕捉到非法操作。

共享页

分页的内存机制,还有一个优先就是可以共享公共代码。
对于一个分时系统,假设有一个支持40个用户的系统,每个用户都指向一个文本编辑器,每个文本编辑器包括150k的代码和50k的数据空间,那么久需要8000kb的内存来支持40个用户。
但是,如果代码是可重入代码。则可以进行共享。

可重入代码是不能自我修改的代码,他在执行期间不会改变。因此两个或者多个进程可以同时执行相同的代码。每个进程都有自己的寄存器和数据存储,以保证数据的正确性和安全。

所以在物理内存中只需要保存一个编辑器的副本,每个用户的页表映射到编辑器的同一个物理副本,但是数据页映射到不同的帧。因此支持40个用户,只需要一个编辑器副本,和40个50k的数据空间,所以只需要2150k,而不是8000k。

上一篇:计算机组成与设计-虚拟内存


下一篇:ARM MMU工作原理剖析