第3章存储管理3.1虚拟存储器3.2内存管理方式3.380386段页机制3.4Linux存储管理3.5小结习题每一个要运行的程序,必须首先进入内存,然而,每一台计算机的内存容量都是有限而宝贵的。存储管理的任务是方便用户使用存储资源,在有限的物理空间内使更多的用户进程高效地获得和使用尽可能多的存储空间,从而提高系统的整体性能。现代操作系统中普遍采用基于虚拟存储器的概念来统一管理内存和外存,实现逻辑上的大容量存储空间。本章首先介绍虚拟存储器的基本概念及使用虚拟存储器的依据和出发点——局部性原理,即在程序的运行过程中,总是集中地访问某一个程序段。根据这样的原理,可以把物理内存按照一定的规则划分为小部分,每次只装入某个进程必要的一部分内容就开始运行,在运行过程中,再根据需要装入新的内容。不同的划分规则形成不同的存储管理技术,我们简单介绍分区、页式、段式和段页式管理的基本思想。接着介绍Intel80386硬件存储管理机制,最后学习Linux系统在这种硬件平台的基本存储管理机制。3.1虚拟存储器计算机系统的存储器分为内存(主存)和外存(硬盘)。内存的价格昂贵,速度高,存储容量有限;外存价格便宜,速度慢,存储容量很大,适合于存放大量数据。为了使更多的用户进程合理、充分地使用存储资源,操作系统统一管理内存和外存,即把内存中暂时不用的内容放在硬盘上,内存中就可以腾出一部分空间,可以从硬盘装入其他迫切需要的内容。因此,从效果上看,计算机系统好像为用户提供了一个其存储容量比实际主存大得多的存储器。人们称这个存储器为虚拟存储器。3.1.1局部性原理实验证明,在几乎所有进程的执行过程中,某一个特定的时间段中,CPU不是随机地访问整个程序或数据,而是集中地访问程序或数据的某一个部分。进程的这种访问特性称为局部性原理。与CPU访问该局部内的数据和代码的次数相比,局部段的变化很缓慢,正是基于这样的原理,我们才有可能实现虚拟存储管理。把进程的所有内容划分为一个个小的部分,首先只把系统所必需的部分数据装入内存,其余部分就放在外存中,开始运行之后,再把所需要的其他部分换入内存,同时把不再需要的部分从内存中换到硬盘或者清除掉。当然,与之相配合,实际的内存也要划分为对应的小部分。这种内外存之间的数据交换对用户进程来讲是透明的。从用户进程的角度来看,系统好像提供了一个很大的内存一样,整个进程都能装进去而且正常运行,这种逻辑上的大容量存储空间就可以称为虚拟存储器。实际上,是操作系统的存储管理起了作用,用多次内外存数据交换的时间换来了大容量的并不真正存在的(虚拟的)内存。因此,可以想象,访问虚拟存储器的速度要比访问真正内存的速度要慢。3.1.2虚拟地址和虚拟地址空间内存中同时存在多个进程,每个进程的地址都是以0地址作为起始地址的虚拟地址空间,这个虚地址空间可以是线性的(一维的),也可以是多维的,这要取决于系统采用的存储管理方式。进程中的每一个指令和数据在这样的虚地址空间中都有一个惟一确定的地址,即虚拟地址。每一个进程都具有各自独立的虚拟地址空间,而整个系统只有一个物理地址空间。任何一个要执行的进程,都必须进入真正的内存中,在内存的物理空间中存在,这就需要在虚拟地址空间和物理地址空间之间建立适当的映射关系。通过这种映射关系,逐部分地把存在于虚拟地址空间中的进程要执行的部分放在物理地址空间中,而其他暂时不执行的部分放在外部存储器中,内外存动态地传递数据,最终完成整个进程所执行的任务。这种映射,也称为地址变换,是操作系统在硬件的配合下实现的。系统中的每一个进程,都有一个惟一的地址映射关系,也就是说,虚拟地址空间到物理地址空间是一个多对一的映射关系。这样,不同的进程有不同的虚拟地址空间和映射变换,可以方便地实现进程之间的存储保护,避免数据和程序遭受其他进程无意或者恶意的访问,同时,它们都映射到惟一的物理空间,可以通过多个进程同时映射同一个物理地址的方式实现数据和程序的共享。3.2内存管理方式虚拟存储的每一个要运行的程序,都必须首先进入内存,但是,每一台计算机的内存容量都是有限而宝贵的。管理技术,通常是基于局部性原理的,即把整个进程的虚拟地址空间划分为小的部分,同时把内存也划分为小的部分,在虚拟地址空间和物理地址空间之间建立特定的映射关系,进程的内容分批分期进入内存中特定的位置,其余部分在外存中,在需要的时候再传递到内存,用内存和外存的统一管理来实现内存扩充。在虚拟存储技术的发展过程中,使用了不同的地址空间划分方法和映射关系,这些不同的划分和映射对应于不同的存储管理方式,本节介绍几种能够实现虚拟存储的地址空间划分方式。3.2.1页把进程的虚拟地址空间划分为相等大小的部分,每个部分称为页(page),同时把物理内存空间也按照页的大小划分为小的部分,称为页面(pageframe,也称为页架或页框)。对于80386体系,页和页面的大小都为4K字节。在页和页面之间建立一一映射关系,连续的一维虚拟地址空间可以分别存放在不同物理空间中,因此,物理存储中,每个页面内部地址连续,而页面之间的地址可以是不连续的。页和页面之间的映射关系记录在一个表格中,这样的表称为页表。每一个进程使用惟一的页表,页表的每一项数据称为页表项,表示虚拟空间中某一页和实际物理空间中某一页面的对应关系,页表也存储在物理空间内,如图3.1所示。图3.1页式管理:页表(左)及相应的页、页面对应关系(右)示意图从上图可以看出,连续的一维虚拟空间经过变换,映射到物理空间中不连续的页面中。利用分页机制实现虚拟存储管理称为页式存储管理。管理过程中,内外存的数据传递是以页为单位。页式管理采用请求调页或者预调页技术实现内外存的统一管理,内存中同时只存放少量经常执行或者即将执行的页,而其他不经常使用或暂时不会执行的页,存放在外存中,等需要的时候再调入内存。利用分页技术将一维连续虚拟空间划分为一个个页,进程的虚拟地址由两个部分组成:页号P和页内地址(偏移量)W。这两个部分的虚拟地址经过地址变换后,映射到物理内存的对应单元。具体的地址变换过程如图3.2所示。图3.2页式内存管理地址变换示意图操作系统为每一个进程维护一个独立的页表,进程正在执行的时候,页表信息记录在页表控制寄存器中,系统根据寄存器的值得到该进程对应页表的地址,同时利用页号,就可以得到该页对应的页表项。查找页表,获得了页表所映射的页面号,由页面号和页内地址,就可以直接找到内存中的对应存储单元。在整个变换过程中,需要两次访问物理内存,第一次是查找页表,第二次是获取数据。为了提高效率,硬件一般提供一个高速的联想寄存器,构成一个快表(translationlookasidebuffer),把当前进程中经常使用的页表项放在快表中,地址变换过程中,首先访问快表,如果该页表项存在于快表中,就可以直接得到对应的页面号,如果不在快表中,再去查找页表得到页面号,快表的访问速度要比内存快得多,这样就可以提高内存的访问速度。采用页式管理,实现了进程的程序和数据非连续存放,对内存和外存统一管理,得到更大的虚拟存储空间,可以同时容纳和运行更多的进程,有利于系统整体性能的提高。缺点是增加了系统开销,而且需要一定的硬件支持。由于虚拟空间是连续的,整个进程按照一维地址顺序排列,同一个程序段在分页的过程中,可能分别位于不同的页中,代码和数据的共享比较困难。3.2.2段段式管理的基本思想是把整个程序按照逻辑结构划分为不同的段,每个段可以是一个函数(过程)或者数据,有自己的名称,段大小是不相等的,段与段之间不存在顺序关系。这样,进程具有一个二维的虚拟空间。内存的管理以段为单位,把正在执行的段放在内存中,其他段暂时放在外存中,当需要执行时再传递到内存中。这样,也可以实现大容量的虚拟存储器。段式管理中,进程的虚拟地址是二维的,由段号和段内偏移地址构成。与页式管理的区别在于,段号是不连续的,段的大小是可变的。在二维虚拟空间与物理空间之间需要建立一一映射关系,即地址变换,这种变换关系记录在一个称为段表的表格中,系统为每一个进程维护一张段表,通过查找段表,就可以得到虚拟地址所对应的物理单元。段式存储管理的优点在于使用了大小可变的虚拟地址空间划分方法,按照程序的固有逻辑关系来分段,便于进程之间存储共享。但是,地址变换关系更为复杂,需要更多的硬件支持,实现起来更为麻烦,同时也带来了更大的系统开销。3.2.3段页段页式存储管理,综合利用段式和页式管理的思想,把整个二维虚拟空间先分段,然后在段内分页。以页为最小的存储管理单位来实现虚拟存储。一方面可以按照程序的逻辑关系来划分进程空间的段,另一方面使用页来存放每一个段的内容,内外存交换以统一格式和大小的页来进行。这种管理模式下,虚拟地址要包括三个部分:段号、页号和页内偏移地址,地址变换也要经过两层次映射才能够实现,首先从二维虚拟空间映射到一个线性虚拟空间,然后再从线性空间映射到物理空间。可以想象,整个变换过程更为复杂,需要大量的硬件支持和系统开销。3.380386段页机制上一节,我们介绍了不同的存储管理方法:页式、段式和段页式。这些方法的依据都是局部性原理,区别在于存储空间的划分和映射方法。这些管理方法都需要一定的硬件支持。本节,针对Linux系统的主要平台之一Intel80386(简称I386)系统,介绍该系统的段页式硬件支持机制。3.3.1实模式与保护模式80386是Intel公司推出的32位CISC芯片,此后,该公司又相继推出80486、Pentium(P5)、PentiumPro、PⅡ、PⅢ等一系列向下兼容的32位芯片。本节讨论的特点是针对以I386为代表的整个芯片系列。I386有两种工作模式,实地址模式和虚拟地址模式,后者又称保护模式。实地址模式与早期的8086兼容,不能启用分页机制,不区分特权级,分段机制也受到限制,直接寻址方式,只能寻址1MB。I386的保护模式支持分段机制,整个虚拟空间可以划分为16K个段,每个段的大小可变,最大能够达到4GB,每个段可以提供独立的段内保护,支持二级分页机制,每个页面4KB,提供段页式存储管理的硬件支持。同时,在同一个任务内部,还提供4种(0~3)保护特权级,某一级特权i只可以访问所有其他大于等于这一特权级(≥i)的程序段。3.3.2地址空间在I386体系结构中,提供段页式存储管理的硬件支持,和内存管理有关的地址空间包括逻辑地址空间、线性地址空间和物理地址空间,在存储过程中,要经过相对独立的两级地址变换。第一级使用分段机制,把包含段地址和段内偏移地址的二维虚拟地址空间转换为一个线性地址空间(也是虚拟地址空间),第二级使用分页机制,把线性地址空间转换为物理地址空间。这种转换关系可以用图3.3来描述。图3.3地址映射关系示意图虚拟地址空间到线性地址空间的转换关系由段描述符表(简称段表)来描述,段表的每一个数据项记录一个段到线性地址的关系,段表存放在线性地址空间中。线性地址空间到物理空间的转换关系由页表描述,页表存放在物理地址空间中。每个虚拟地址空间(16K个段)可以分为相等的两个部分,一半称为全局虚拟地址空间,由全局段描述符表(GlobalDescriptorLabel,GDT)映射,另一半称为局部虚拟地址空间,由局部段描述符表(LocalDescriptorLabel,LDT)映射。系统中所有进程共享一个全局段表(GDT),而每一个进程都有自己的局部段表(LDT)。当进程发生切换时,GDT不变,而LDT更新为正在执行进程的LDT,因此,所有进程共享GDT所映射的物理地址空间,每一个进程都有自己单独的地址空间(由LDT描述)。线性地址空间划分为大小相等的页,每页为4KB,与之对应的物理地址空间划分为大小相等的页面,页面的大小也是4KB。I386体系结构采用二级分页机制,线性地址到物理地址的映射使用一个二级页表,二级表中的第一级称为页目录,每个页目录项指向一个二级表,这个二级表就是一个页表,每一个表项记录该表对应的表架的基地址,这个基地址和偏移量一起就构成整个物理地址。3.4Linux存储管理Linux系统本身采用段页式存储管理,使用