一 多层结构存储器
计算机运行时,几乎每条指令都要设计存储器的访问,因此存储器的速度必须要能和处理机运行速度相匹配,不然就会影响处理机的运行,并且存储器的容量要足够大,还得便宜,目前肯定是无法满足,所以现代操作系统几乎都采用多层结构的存储器系统。多层结构如图A所示,最高层是寄存器(速度不亚于CPU,但是价格昂贵),中间是主存,最后是辅存。
为了解决CPU与主存的速度差异引入了高速缓存。其中,寄存器、高速缓存、主存储器都属于操作系统存储管理,在发生故障停电的话,其中的数据就消失了,其他更底层的比如磁盘则属于设备管理,信息可以长期保存。
但是,对于寄存器、主存和辅存的访问机制是不同的。寄存器、主存又被称为可执行存储器,进程可以通过很少的周期通过指令访问。对于辅存,那是通过设备管理的,要通过I/O设备实现访问,经过I/O设备的话就涉及到中断、设备驱动程序、以及物理设备等,所以速度相对可执行存储器来说要慢要几个数量级。所以这也是我们平常写的程序要加载到内存执行的原因之一吧!
二 存储器的分配方式
我们都知道用户程序需要装入到内存中才能运行,那么存储器怎样为用户程序分配存储空间,如何对内存进行管理。如下有四种管理方式
1. 连续分配存储管理
连续分配方式是最早出现的存储器分配,该方式为用户程序分配连续的内存空间,即程序代码或数据的逻辑地址相邻,体现为物理地址的相邻,连续分配又分为四类
-
A. 单一连续分配
最早的单道程序环境,存储器管理方式把内存分为系统区和用户区,系统区OS使用,用户 区只有一道用户程序,整个用户区都是这个程序的,所以就是单一连续分配。
-
B. 固定分区分配
多道程序系统的出现,使得需要在内存中装入多道程序,但程序之间相互之间不能干扰,所以就将用户空间分为若干个固定大小区域,每个区域装入一道作业。在为用户空间划定大小区域时可以分成大小相等的,那么程序太小时就太浪费空间,如果太大就无法运行,另一种就是不等的大小空间,这样可以根据不同作业选择空间。大体如图所示:
-
C. 动态分区分配
动态分区分配言外之意就是要根据进程的实际需要而分配内存空间,那么这个 过程就要涉及管理空间的数据结构,分配算法,以及分配和回收的问题。
数据结构
通过一个数据结构来描述空闲分区和已分配空间,通常有空闲分区表和空闲分区链两种,如下图所示:
分配算法
程序装入内存,肯定要经过某种算法从空闲分区表或者分区链选择分区,这个所说的算法就有七种:基于顺序搜索的有:首次适应(FF)、循环首次适应(NF)、最佳适应(BF)、最坏适应(WF);基于索引搜索的有快速适应、伙伴系统、哈希算法 -
D. 动态可重定位分区分配
采用上述的方法肯定回造成碎片而导致浪费,所有这里采用移动的方式将程序紧凑,碎片就可以拼接成大空间,但是这样的话会导致程序和数据的地址发生改变,所以引入了动态重定位。
动态重定位:在程序装入内存时仍然采用相对地址,当指令真正执行的时候才借助重定位寄存器将相对地址转化为绝对地址。
2. 对换技术
对换技术又称为交换技术,在以前内存很小的时候为了让多道程序运行,程序存储在磁盘,加载一道程序到内存运行,CPU时间片结束过后调到磁盘然后调度另一道程序,进程具体的换出换入操作这里不讨论。
3. 分页存储管理
前面说的连续分配方式会产生很多的碎片,虽然紧凑可以解决,但是需要很大的开销,于是就出现将进程分散的装入不相邻的分区的想法,这样就不会有碎片了。基于这种思想出现了分页存储管理、分段存储管理、段页式存储管理。
分页存储管理中,将用户程序的地址空间分为若干个大小相同的区域成为页,大小一般是1KB,然后内存空间页分为若干个块,页和块的大小相同,通过这种方式任何页都可以放入任何块,达到离散分配的目的。以下介绍来自百度百科。
页面
- 页面和物理块
分页存储管理是将一个进程的逻辑地址空间分成若干个大小相等的片,称为页面或页,并为各页加以编号,从0开始,如第0页、第1页等。相应地,也把内存空间分成与页面相同大小的若干个存储块,称为(物理)块或页框(frame),也同样为它们加以编号,如0#块、1#块等等。在为进程分配内存时,以块为单位将进程中的若干个页分别装入到多个可以不相邻接的物理块中。由于进程的最后一页经常装不满一块而形成了不可利用的碎片,称之为“页内碎片”。 - 页面大小
在分页系统中的页面其大小应适中。页面若太小,一方面虽然可使内存碎片减小,从而减少了内存碎片的总空间,有利于提高内存利用率,但另一方面也会使每个进程占用较多的页面,从而导致进程的页表过长,占用大量内存;此外,还会降低页面换进换出的效率。然而,如果选择的页面较大,虽然可以减少页表的长度,提高页面换进换出的速度,但却又会使页内碎片增大。因此,页面的大小应选择适中,且页面大小应是2的幂,通常为512 B~8 KB。
地址结构
分页地址中的地址结构如下:
对于某特定机器,其地址结构是一定的。若给定一个逻辑地址空间中的地址为A,页面的大小为L,则页号P和页内地址d可按右图所示公式求得:
其中,INT是整除函数,MOD是取余函数。例如,其系统的页面大小为1 KB,设A = 2170 B,则由上式可以求得P = 2,d = 122。
页表
在分页系统中,允许将进程的各个页离散地存储在内存不同的物理块中,但系统应能保证进程的正确运行,即能在内存中找到每个页面所对应的物理块。为此,系统又为每个进程建立了一张页面映像表,简称页表。在进程地址空间内的所有页(0~n),依次在页表中有一页表项,其中记录了相应页在内存中对应的物理块号,见右图的中间部分。在配置了页表后,进程执行时,通过查找该表,即可找到每页在内存中的物理块号。可见,页表的作用是实现从页号到物理块号的地址映射。
4. 分段存储管理
分页式存储管理很好的提高了内存的利用率,那么分段式存储则是从程序员的角度出发,方便程序员的开发。
通常,我们的程序本身都可以分为若干个段,主程序段,子程序段,数据段,栈段,如果你学了汇编会有更深刻的体会。再一个就是我们信息的共享、保护、动态连接等也都是以段为单位,所以分段存储管理更符合程序员的需要。
基本原理(来自百度百科)
分段
在分段存储管理方式中,作业的地址空间被划分为若干个段,每个段定义了一组逻辑信息。例如,有主程序段MAIN、子程序段X、数据段D及栈段S等,如图4-17所示。每个段都有自己的名字。为了实现简单起见,通常可用一个段号来代替段名,每个段都从0开始编址,并采用一段连续的地址空间。段的长度由相应的逻辑信息组的长度决定,因而各段长度不等。整个作业的地址空间由于是分成多个段,因而是二维的,亦即,其逻辑地址由段号(段名)和段内地址所组成。
分段地址中的地址具有如下结构:
在该地址结构中,允许一个作业最长有 64 K个段,每个段的最大长度为64 KB。 分段方式已得到许多编译程序的支持,编译程序能自动地根据源程序的情况而产生若干个段。例如,Pascal编译程序可以为全局变量、用于存储相应参数及返回地址的过程调用栈、每个过程或函数的代码部分、每个过程或函数的局部变量等等,分别建立各自的段。类似地,Fortran编译程序可以为公共块(Common block)建立单独的段,也可以为数组分配一个单独的段。装入程序将装入所有这些段,并为每个段赋予一个段号。
段表
在前面所介绍的动态分区分配方式中,系统为整个进程分配一个连续的内存空间。而在分段式存储管理系统中,则是为每个分段分配一个连续的分区,而进程中的各个段可以离散地移入内存中不同的分区中。为使程序能正常运行,亦即,能从物理内存中找出每个逻辑段所对应的位置,应像分页系统那样,在系统中为每个进程建立一张段映射表,简称“段表”。每个段在表中占有一个表项,其中记录了该段在内存中的起始地址(又称为“基址”)和段的长度,如右图所示。段表可以存放在一组寄存器中,这样有利于提高地址转换速度,但更常见的是将段表放在内存中。
5. 段页式存储管理
分页系统能提高内存的利用率,分段系统能够满足用户的需要,所以对两种存储方式“各取所长”,得到段页式存储管理方式(现在基本都在使用)。
基本原理
段页式系统先将用户程序分成若干个段,在把每个段分为若干个页。地址结构就由段号段内页号,以及页内地址组成。段表内容略有不同,如果所示:通过这种方式将逻辑地址转化为物理地址。