操作系统(四)——存储器管理

存储器的层次结构

对于通用计算机而言,存储层次至少为三级:CPU寄存器、主存、辅存。
计算机存储示意图

什么是位?
所谓位,是最基本的概念,在计算机中,由于只有逻辑0和逻辑1的存在,因此很多东西、动作、数字都要表示为一串二进制的字码例如: 1001 0000 1101等等。其中每一个逻辑0或者1便是一个位。例如这个例子里的1000 1110共有八个位,它的英文名字叫(bit),是计算机中最基本的单位。
所谓的字节 Byte,是由八个位组成的一个单元,也就是8个bit组成1个Byte。字节有什么用呢? 在计算机科学中,用于表示ASCII字符,便是运用字节来记录表示字母和一些符号~例如字符A便用 “0100 0001”来表示。
而字节以上,便是字:16个位为一个字,它代表计算机处理指令或数据的二进制数位数,是计算机进行数据存储和数据处理的运算的单位。通常称16位是一个字,而32位呢,则是一个双字,64位是两个双字。
xx位机的xx位是指字长。这个字和word不一样,是指这种CPU一次能运算的数据长度,32位机就是一次运算32个二进制位,64位机就是一次运算64个二进制位。

程序的装入和链接

在多道程序环境下,要使程序运行,必须先为之创建进程。而创建进程的第一件事,便是将程序和数据装入内存。
用户源程序变成可执行程序的步骤:

  • 编译:由编译程序(Compiler)将用户源代码编译成若干个目标模块(Object Module);
  • 链接:由链接程序(Linker)将编译后形成的一组目标模块,以及它们所需要的库函数链接在一起,形成一个完整的装入模块(Load Module);
  • 装入:由装入程序(Loader)将装入模块装入内存。

连续分配方式

连续分配方式是指,为用户程序分配一个连续的内存空间。又可把连续分配方式进一步分为单一连续分配、固定分区分配、动态分区分配以及动态重定位分区分配四种方式。

单一连续分配

只能用于单用户、单任务的操作系统中。采用这种存储管理方式时,可把内存分为系统区和用户区两部分,系统区仅提供给OS使用,通常是放在内存的低址部分;用户区是指除系统区以外的全部内存空间,提供给用户使用。

固定分区分配

固定分区分配是一种可运行多道程序的存储管理方式。它将内存用户空间划分为若干个固定大小的区域,在每个分区中只装入一道作业,这样,把用户空间划分为几个分区,便允许有几道作业并发运行。
为了便于内存分配,通常将分区按大小进行排队,并为之建立一张分区使用表,其中各表项包括每个分区的起始地址、大小及状态。

动态分区分配

动态分区分配是根据进程的实际需要,动态地为之分配内存空间。在实现可变分区分配时,将涉及到分区分配中所用的数据结构、分区分配算法和分区的分配与回收操作这样三个问题。
(1) 分区分配中的数据结构
空闲分区表和空闲分区链。
(2) 分区分配算法

  • 首次适应算法(FF,first fit):FF要求空闲分区链以地址递增的次序链接。在分配内存时,从链首开始顺序查找,直至找到一个大小能满足要求的空闲分区为止,会优先从内存中的低地址进行查找分配。
  • 循环首次适应算法(NF,next fit):NF由FF演变,不再是每次都从链首开始查找,而是从上次找到的空闲分区的下一个空闲分区开始查找,直至找到一个能满足要求的空闲分区,从中划出一块与请求大小相等的内存空间分配给作业。
  • 最佳适应算法啊(BF,best fit):每次为作业分配内存时,总是把能满足要求、又是最小的空闲分区分配给作业,避免“大材小用”。
  • 最坏适应分配算法(worst fit):扫描整个空闲分区表或链表,总是挑选一个最大的空闲区分割给作业使用分区的分配与回收。
  • 快速适应算法(quick fit):该算法又称为分类搜索法,是将空闲分区根据其容量大小进行分类。

(3) 分区的分配与回收操作
在动态分区存储管理方式中,主要的操作是分配内存和回收内存。

动态重定位分区分配

基本分页存储管理方式

推动存储管理方式从固定分区到动态分区,进而发展到分页管理的主要动力是,提高内存利用率。
在分页存储管理方式中,如果不具备页面对换功能,则称为基本的分页存储管理方式,或称为纯分页存储管理方式,它不具有支持实现虚拟存储器的功能,它要求把每个作业全部装入内存后方能运行。

引入

1)页面和物理块
分页存储管理是将一个进程的逻辑地址分为若干大小相等的片,称为页面或页,并为各页编号。也把内存空间分为与页面大小相等的若干存储块,称为(物理)块或页框(frame),并对块与进行编号。
页面大小的选取应当适中,且为2的幂,通常为512B~8KB。
2)地址结构
分页地址中的地址结构为:分也式逻辑地址=页号P+页内地址(位移量)d
对于某个特定机器,其地址结构是一定的。若给定一个逻辑空间中的地址A,页面大小L,则可以求得其页号P和页内地址d:

1
2
P=floor(A / L),向下取整
d=A mod L,取余

如给定一个逻辑地址空间的地址A=2170 B,系统页面大小为1KB,则由上面两个式子得到页号P=2017/1024=2,页内地址d=2017 mod 1024=122。
3)页表
在分页系统中,允许将进程的各个页离散地存储在内存不同的物理块中,但系统应能保证进程的正确运行,即能在内存中找到每个页面所对应的物理块。为此,系统又为每个进程建立了一张页面映像表(页表)。页表的作用是实现从页号物理块号的地址映射
页表的作用

地址变换机构

地址变换机构的主要作用是实现从逻辑地址到物理地址的转换。具体地,将逻辑地址的页号转换为内存中的物理块号。又由于页面映射表(页表)的作用就是实现页号到物理块号的映射,因此地址变换的主要任务是借助页面映射表(页表)来完成的。
1)基本的地址变换机构
当进程未执行时,页表的始址和页表的长度都存在本进程的PCB中;当调度程序调度到某进程时,才将这两个数据装入页表寄存器。
计算某个分页管理中逻辑地址的物理地址
找到逻辑地址的页号;计算在页表中的地址=页表始址+页号*页表项长度;通过页表映射到物理地址
![分页系统的地址变换机构]default

2) 具有快表的地址转换机构

基本分段存储管理方式

引入

引入基本分段存储管理方式的目的是,满足开发人员在编程和使用上的多方要求:

  • 方便编程:逻辑地址=段号+段内地址(偏移);
  • 信息共享:段是信息的逻辑单位,而页只是存放信息的物理单位(块),并无完整意义。允许多个进程共享一个或多个分段。
  • 信息保护:对信息的逻辑单位进行保护。
  • 动态增长,
  • 动态链接:在作业运行之前,并不把作业段链接起来,而是在运行过程中需要调用某段时,才将该段调入内存并连接。

分段系统的原理

1)分段
分段式逻辑地址=段号+段内地址。整个作业的地址空间由于是分成多个段,因而是二维的。
作业的地址空间被划分为若干个段,每个段定义了一组逻辑信息。例如,有主程序段MAIN、子程序段X、数据段D 及栈段S段,每个段都有自己的名字。
2)段表
对应于分页管理中的页表,分段管理中也有段表,用于实现逻辑段到物理内存区的映射
3)地址变换机构
计算分段管理中某个逻辑地址的物理地址
找到逻辑地址的段号;根据段表始址和段号,计算该段对应表项的位置,从中读出该段在内存中的起始地址;计算物理地址=起始地址+段内地址;通过页表映射到物理地址
分段系统的地址变换机构

4)分页和分段的主要区别
a. 页是信息的物理单位,分页是为了提高内存利用率;段是信息的逻辑段位,分段是为了满足用户的需要。
b. 页的大小固定且由系统决定;段的大小不固定,由用户所编写的程序决定。
c. 分页的作业地址空间是一维的;分段的作业地址空间是二维的,在标识地址时,既要给出段名,又要给出段内地址。
怎么理解分页管理是一维的,而分段管理是二维的?
页式存储是一维的,因为各个模块在链接时必须组织在同一地址空间;而分段式二维的,各个模块在链接时可以把每个段组织成一个地址空间。也就是说,在编程的时候,如果是分页存储,你只需要给定一个逻辑地址,然后操作系统会自己去把逻辑地址划分成页号和页内偏移,所以是一维的。而如果是段式存储的话,你需要给定的逻辑地址必须包括段号和段内偏移量,因为分段式从程序员的角度来分的,操作系统并不知道段内偏移,无法只通过段号找物理地址,所以段式存储是二维的。
5)段页式存储管理
分页能提高内存利用率,而分段能满足用户需求。
段页式存储是分段和分页原理的结合,即先将用户程序分成若干个段,再把每个段分成若干个页,并为每一个段赋予一个段名。
段页式逻辑地址=段号+段内地址+页内地址

虚拟存储器

引入

前面所说的存储器都需要将所有作业放入内存才能运行,但并非所有程序和数据都用得到,而且作业会一直驻留在内存,直到作业运行结束。但可能出现内存容量不够大的情况,因此出现了虚拟存储器的概念。
局部性原理:
程序在执行时将呈现局部性规律,即在一较短时间内,程序的执行仅局限于某个部分,相应地,它访问的内存区域也局限于某个区域。体现在:

  • 时间局限性:如果程序中的某条指令被执行过,则该条指令可能再次被执行;或该条数据被访问过,则它有可能被再次访问。
  • 空间局限性:如果程序的某个存储单元被访问过,则它附近的单元可能在不久后被访问。

基于局部性原理,应用程序在执行之前,没必要全部装入内存。

虚拟存储器的实现方法

1) 分页请求系统

2) 分段请求系统

请求分页存储管理方式

请求分页存储管理是建立在基本分页存储管理方式上的。为了能支持虚拟存储器功能,增加了调页功能和页面置换功能

页面置换算法

在进程运行过程中,若其要访问的页面不在内存且需要调入内存,但内存中已无空闲空间时,系统必须从内存中调出一页或数据送往磁盘的对换区中。把选择换出页面的算法称为页面置换算法(page replacement algorithm)。

最佳(optimal)置换算法

最佳置换算法是Belady提出的一种理论上的算法。它所选择的淘汰页面是,以后将永不再使用的,或许在最长(未来)时间内不再被访问的页面。可以保证最低的缺页率。
如系统为某个进程分配了三个物理块,考虑如下的页面号引用串:
7,0,1,2,0,3,0,4,2,3,0,3,2,1,2,0,1,7,0,1
先将7,0,1转入内存,当要访问页面2时,将产生缺页中断,根据最佳置换算法,选择将页面7淘汰。因为页面7将在第18次访问才调入,页面0将在第5次访问调入,页面1将在第14次访问时调入,所以页面7将是最晚访问的,需要被淘汰。从下图可以看出产生了6次页面置换。
最佳页面置换算法

先进先出(FIFO,first in first out)置换算法

先进先出总是淘汰最先进入内存的页面,即选择在内存中驻留时间最久的页面予以淘汰。
仍然使用上面的例子,从下图可以看出FIFO算法执行了12次页面置换。
FIFO置换算法

最近最久未使用(LRU,least recently used)置换算法

最近最久未使用算法选择最近最久未使用的页面予以淘汰。仍然使用上面的例子,由下图可以看出,LRU算法进行了9次页面置换。需要硬件支持。
LRU页面置换算法

Clock置换算法

LRU 算法是较好的一种算法,但由于它要求有较多的硬件支持,故在实际应用中,大多采用LRU的近似算法。Clock算法就是用得较多的一种LRU近似算法。
由于该算法是循环地检查各页面的使用情况,故称为Clock算法。置换时是将未使用过
的页面换出去,所有又叫最近未用(NRU,not recently used)算法。需要硬件支持。

最少使用(LFU,least frequency used)页面置换算法

LFU算法选择在最近使用次数最少的页面作为淘汰页。
设置移位寄存器来记录页面使用的频率,每次访问某个页面时,便将该移位寄存器的最高位置1,再每隔一段时间(如100ms)右移一次。没有使用计数器的原因是存储器的访问速度太高。

页面缓冲算法(PBA,page buffering algorithm)

页面缓冲算法规定将一个被淘汰的页放入两个链表中的一个,即如果页面未被修改,就将它直接放入空闲链表中;否则,便放入已修改页面的链表中。须注意的是,这时页面在内存中并不做物理上的移动,而只是将页表中的表项移到上述两个链表之一中。