内存是用于存放数据的硬件。程序在执行前需要先放到内存中才能被CPU处理。
如果字长为16位的计算机“按字编址”,则每个存储单元大小为1个字;每个字的大小为16个二进制位。
如果计算机“按字节编址”则每个存储单元大小为1字节,即1B,即8个二进制位。
编译: 由编译程序将用户源代码编译成若干个目标模块(编译就是把高级语言翻译为机器语言)。
链接: 由链接程序将编译后形成的一组目标模块,以及所需库函数链接在一起,形成一个完整的装入模块。
装入(装载): 由装入程序将装入模块装入内存运行。
1、绝对装入: 在编译时,如果知道程序将放到内存中的哪个位置,编译程序将产生绝对地址的目标代码。装入程序按照装入模块中的地址,将程序和数据装入内存。
只适用于单道程序环境
2、静态重定位: 又称可重定位装入。编译、链接后的装入模块的地址都是从0开始的,指令中使用的地址、数据存放的地址都是相对于起始地址而言的逻辑地址。可根据内存的当前情况,将装入模块装入到内存的适当位置。装入时对地址进行“重定位”,将逻辑地址变换为物理地址(地址变换是在装入时一次完成的)。
在作业装入时,必须分配其要求的全部内存空间,作业一旦进入内存后,在运行期间不能再移动,也不能再申请内存空间。
3、动态重定位: 又称动态运行时装入。编译、链接后的装入模块的地址都是从0开始的。装入程序把装入模块装入内存后,并不会立即把逻辑地址转换为物理地址,而是把地址转换推迟到程序真正要执行时才进行。因此装入内存后所有的地址依然是逻辑地址。这种方式需要一个重定位寄存器的支持。
允许程序在内存中发生移动
1.静态链接: 在程序运行之前,先将各目标模块及它们所需的库函数连接成一个完整的可执行文件(装入模块),之后不再拆开。
2.装入时动态链接: 将各目标模块装入内存时,边装入边链接的链接方式。
3.运行时动态链接: 在程序执行中需要该目标模块时,才对它进行链接。其优点是便于修改和更新,便于实现对目标模块的共享。
功能:
1)连续分配(为用于进程分配的必须是一个连续的内存空间)管理方式:
a)单一连续分配: 在单一连续分配方式中,内存被分为系统区和用户区。系统区通常位于内存的低地址部分,用于存放操作系统相关数据;用户区用于存放用户进程相关数据。
内存中只能有一道用户程序,用户程序独占整个用户区空间。
优点: 实现简单;无外部碎片;可以采用覆盖技术扩充内存;不一定需要采取内存保护(eg:早期的PC操作系统MS-DOS)。
缺点: 只能用于单用户、单任务的操作系统中;有内部碎片;存储器利用率极低。
b)固定分区分配: 为了能在内存中装入多道程序,且这些程序之间又不会相互干扰,于是将整个用户空间划分为若干个固定大小的分区,在每个分区中只装入一道作业。
分区大小相等: 缺乏灵活性,但是很适合用于用一台计算机控制多个相同对象的场合。
分区大小不等: 增加了灵活性,可以满足不同大小的进程需求。根据常在系统中运行的作业大小情况进行划分(比如:划分多个小分区、适量中等分区、少量大分区)
建立数据结构——分区说明表(包括:对应分区的大小、起始地址、状态)
优点: 实现简单,无外部碎片。
缺点: a.当用户程序太大时,可能所有的分区都不能满足需求,此时不得不采用覆盖技术来解决,但这又会降低性能; b.会产生内部碎片,内存利用率低。
c)动态分区分配(可变分区分配)。这种分配方式不会预先划分内存分区,而是在进程装入内存时,根据进程的大小动态地建立分区,并使分区的大小正好适合进程的需要。因此系统分区的大小和数目是可变的。
记录内存使用情况的方式:
空闲分区表: 空闲分区对应一个表项,表项中包含分区号、分区大小、分区起始地址等信息。
空闲分区链: 每个分区的起始部分和末尾部分分别设置前向指针和后向指针。起始部分处还可记录分区大小等信息。
内部碎片: 分配给某进程的内存区域中,如果有些部分没有用上。
外部碎片: 是指内存中的某些空闲分区由于太小而难以利用。
1)基本分页存储管理: 把内存分为一个个相等的小分区,再按照分区大小把进程拆分成一个个小部分。
页号=逻辑地址/页面长度(取除法的整数部分)
页内偏移量=逻辑地址%页面长度(取除法的余数部分)
如果每个页面大小为2^k B,用二进制数表示逻辑地址,则末尾k位即为页内偏移量,其余部分就是页号。
为了能知道进程的每个页面在内存中存放的位置,操作系统要为每个进程建立一张页表。
1.一个进程对应一张页表
2.进程的每一页对应一个页表项
3.每个页表项由“页号”和“块号”组成
4.页表记录进程页面和实际存放的内存块之间的对应关系
每个页表项的长度是相同的,页号是“隐含”的。
2)基本分段存储管理
3)段页式存储管理
1)覆盖技术: 常用的部分放在固定区,不常用的部分,放在覆盖区,用的时候再调用。
必须由程序员声明覆盖结构,操作系统完成自动覆盖。
缺点:对用户不透明,增加了用户编程负担。
2)交换(对换)技术: 内存空间紧张时,系统将内存中某些进程暂时换出外存,把外存中某些已具备运行条件的进程换入内存(进程在内存与磁盘间动态调度)。对换的进程应该是在磁盘中的对换区保存的进程,因为对换区(采用连续分配方式)的I/O速度比文件区(为了提高利用率,采用离散分配方式)更快。
1)设置上下限寄存器,存储能够访问的地址上下限
2)设置重定位寄存器(保存初始地址)、界地址寄存器(保存最多能访问的地址数量) 进行判断。
1、首次适应算法(First Fit): 每次都从低地址开始查找,找到第一个能满足大小的空闲分区。按地址递增的次序链接
2、最佳适应算法(Best Fit): 由于动态分区分配是一种连续分配方式,为各进程分配的空间必须是连续的一整片区域。因此为了保证当“大进程”到来时能有连续的大片空间,可以尽可能多地留下大片的空闲区,即,优先使用更小的空闲区。按容量递增次序链接
3、最坏适应算法(Worst Fit)/最大适应算法: 为了解决最佳适应算法的问题――即留下太多难以利用的小碎片,可以在每次分配时优先使用最大的连续空闲区,这样分配后剩余的空闲区就不会太小,更方便使用。按容量递减次序链接
4、邻近适应算法(Next Fit): 每次都从上次查找结束的位置开始检索,以减少查找的开销。按地址递增的次序链接
存放页表在内存中的起始地址F和页表长度M。进程未执行时,页表的始址和页表长度存放在进程控制块(PCB)中,当进程被调度时,操作系统内核会把它们放在页表寄存器中。
注意:页面大小是2的整数幂
设页面大小为L,逻辑地址A到物理地址E的变换过程如下:
①计算页号Р和页内偏移量W(如果用十进制数手算,则P=A/L,W=A%L;但是在计算机实际运行时,逻辑地址结构是固定不变的,因此计算机硬件可以更快地得到二进制表示的页号、页内偏移量)
②比较页号P和页表长度M,若P≥M,则产生越界中断,否则继续执行。(注意:页号是从0开始的,而页表长度至少是1,因此P=M时也会越界)
③页表中页号P对应的页表项地址=页表起始地址F+页号P页表项长度,取出该页表项内容b,即为内存块号。(注意区分页表项长度、页表长度、页面大小的区别。页表长度指的是这个页表中总共有几个页表项,即总共有几个页;页表项长度指的是每个页表项占多大的存储空间;页面大小指的是一个页面占多大的存储空间;所有的页表项长度加起来等于页面大小)
④计算E= bL+w,用得到的物理地址E去访存。(如果内存块号、页面偏移量是用二进制表示的,那么把二者拼接起来就是最终的物理地址了)
页式管理中地址是一维的
时间局部性: 如果执行了程序中的某条指令,那么不久后这条指令很有可能再次执行;如果某个数据被访问过,不久之后该数据很可能再次被访问。(因为程序中存在大量的循环)
空间局部性: 一旦程序访问了某个存储单元,在不久之后,其附近的存储单元也很有可能被访问。(因为很多数据在内存中都是连续存放的)
又称为联想寄存器(TLB) ,是一种访问速度比内存快很多的高速缓冲存储器,用来存放当前访问的若干页表项,以加速地址变换的过程。
内存中的页表常称为慢表。
按照程序自身的逻辑关系划分为若干个段,每个段都有一个段名。每段从0开始编址。
内存分配原则:以段为单位进行分配,每个段在内存中占据连续空间,但各段之间可以不相邻。
用户变成更方便,程序的可读性更高。
分段系统的逻辑地址结构:段号(高位)+段内地址(低位)
段号决定了每个进程最多可以分为多少
段内地址决定了每个段的最大长度
为了从物理地址中找到各个逻辑段的存放位置,系统为每个进程建立了一张段映射表,简称段表
分页中,页表内每个页的长度是相同的,分段中,段表内每个段的长度可以是不同的,但是段表页长度是相同的。
1、页是信息的物理单位,分页的主要目的是为了实现离散分配,提高内存利用率。分页仅仅是系统管理上的需要,完全是系统行为,对用户是可不见的。
2、段是信息的逻辑单位,分段的主要目的是更好的满足用户需求,一个段通常包含着一组属于一个逻辑模块的信息,分段对用户是可见的,用户编程时需要显示的给出段名。
3、页的大小是固定的且是由系统决定的,段的长度是不固定的,取决于用户编写的程序。
4、分页的用户进程地址空间是一维的,程序员只需要给出一个记忆符就可以表示一个地址。(各个页都是连续的,知道起始位置,然后位偏移量,就可以找到)
5、分段的用户进程地址空间是二维的,程序员在标识一个地址时,既要给出段名,又要给出段内地址。(主要是因为段是离散的)
6、分段 比分页更容易实现信息的共享和保护
优点 | 缺点 | |
---|---|---|
分页管理 | 内存空间利用率高,不会产生外部碎片,只会有少量的页内碎片 | 不方便按照逻辑模块实现信息的共享和保护 |
分段管理 | 很方便按照逻辑模块实现信息的共享和保护 | 如果段长过大,为其分配很大的连续空间会很不方便,段式管理会产生外部碎片 |
地址结构是二维的
31 … 16 | 15…12 | 11…0 |
---|---|---|
段号 | 页号 | 页内偏移量 |
决定了每个进程最多有几个段 | 决定了每个段最多有几个页 | 决定了每个页的页面大小、内存块大小 |
段表记录的是:段号、页表长度、页内存放地址,每个段表项长度相等,段号是隐含的。
页表记录的是:页号、内存块号,每个页表项长度相等,页号是隐含的。
一个进程对应一个段表,但是一个进程可以对应多个页表。