第三章 内存管理
储存器的层次结构
层次结构:
因为成本和传输速度的约束,很难做到只用一种储存装置,所以使用速度又快到慢,成本由高到低的储存层次:
存储管理的目的:
- 内存分配:离散分配、连续分配方式
- 地址映射:逻辑地址转化为物理地址,与分配方式有关
- 内存保护:基于地址的保护,存取访问控制保护
- 内存“扩充”:对换技术、虚拟存储技术
基本概念:
- 定位(存储分配):为具体的程序和数据分配存储单元或存储区工作。
- 映射:把逻辑地址转换为相应的物理地址的过程。
- 隔离:按存储权限把合法区和非法区分隔,实现存储保护。
- 名空间:
- 程序员在程序中定义的标识符
- 由程序员自定义
- 没有地址概念 - 地址空间:
- 程序用来访问信息所用的地址单元的集合
- 逻辑(相对)地址的集合
- 由编译程序 生成 - 存储空间:
- 主存中物理单元的集合
- 物理(绝对)地址的集合
- 由装配程序 生成 - 逻辑地址(相对地址,虚地址):用户的程序经过汇编或编译后形成的目标代码,目标代码通采用相对地址的形式,首地址为 0,其余指令中的地址都是对于首地址而编址。不能用逻辑地址在内存中读取信息。
- 物理地址(绝对地址,实地址):内存中存储单元的地址,可直接寻址。
- 存储共享:是进程共用内存中相同的区域,可以代码共享(纯代码),也可以数据共享。
- 存储保护和安全:目的:为多个程序共享内存提供保障,是内存的各道程序只能访问他们自己区域。
- 1)存储保护:
* 保护系统程序区不被用户侵犯
* 不允许用户程序读写不属于自己地址空间的数据
- 2)过程保护–防止地址越界:
* 每个进程都有自己独立的进程空间,若一个进程在运行时产生的地址在空间外,则发生地址越界。然后产生越界中断,交给操作系统处理。
程序的装配和链接
1.程序处理的基本过程
步骤:
- 由相应的语言处理程序(汇编或编译程序)将源程序模块转换为目标模块。
- 由链接程序将所有相关的目标模块以及它们所需要的库例程链接在一起,整合并形成一个装入模块
- 由装入程序将装入模块装入内存然后予以执行。
说明:
- 对统一程序的目标模块进行链接时,通常由于各目标模块原起始地址在绝大多数情况下都相同,都是0。所以要各目标模块的起始地址进行适当调整,以确保整个程序所有目标模块中的数据和代码拥有不同的地址空间和地址值,同时还应修改与地址取值相关的地址敏感代码(地址指令和地址数据),保证链接结果的正确性。
- 无论是装入还是链接和翻译的时候的地址,只要是相对于目标模块的起始地址(通常为0)计算得到的,称为相对地址。而与实际装入内存的起始地址计算而得到的地址,为物理地址或绝对地址。
-
程序的装入:
有三种装入方式,装入模块一般有程序前缀部分和程序正文部分构成,前缀包括程序名、大小、程序执行起始地址,程序装入起始地址、重定位表,动态链接表等管理控制信息。-
绝对装入方式:指由装入程序根据装入模块给定的起始装入地址和装入空间,将程序直接装入到内存并予以执行。不仅要求程序员熟悉内存的使用情况,意思是程序在链接变成装入模块时采用的就是绝对地址,程序在装入内存时不需要进行地址转换,而且一旦程序或者数据被修改,要修改程序中所有的地址。(所以通常是宁可在程序中采用符号地址,然后在编译或者汇编时,转换成绝对地址。链接程序和装入程序相对独立。
-
可重定位装入方式:因为多道程序环境下各程序在内存的起始装入地址和空间往往是不可预知的。程序链接所产生的目标的模块采用相对地址。所以必须分两种:
- 静态可重定位:程序装入时一次性完成程序中所有地址敏感指令和数据的修正后且不再修改(即相对地址到绝对地址的转换)
- 动态可重定位:程序装入时不进行程序中相对地址到绝对地址的转换,而是伴随着程序的执行进展来逐步进行程序中相关地址敏感指令及数据的地址修正。
-
运行时链接装入方式: 前摇(可不看): 因为前两种装入方式一般要求装入模块时由整个程序所有目标模块以及库例程目标模块经链接和整合构成的可执行文件,在程序启动之前就已经完成了程序的链接过程,但在实际生活中很难知道本次要运行哪些模块,所以就有了运行时链接装入方式。
这是一个分割线
在程序执行和调用到动态链接库例程时才进行相应的链接装入操作,知道程序执行到对应的指令时才进程相对地址到绝对地址的转换。
-
-
程序的链接
也分三种:
1. 静态链接方式:链接程序和装入程序相对独立,
2. 动态链接方式:指链接程序和装入程序一起运行(不独立)。
3. 运行时链接方式:先不将程序链接和装入,等到执行和调用到动态链接库例程时才进行相应的链接装入操作,直到程序程序执行到对应指令的时候才进行相对地址到绝对地址的转换。
连续分配方式
每个内存位于一个连续的内存空间内。
单一连续内存管理
采用单一连续内存管理方式时,内存空间的划分十分简单,只划为系统区和用户区,用户占用区是一个连续的储存区所以叫单一连续储存管理。
单一连续区分配采用静态分配和静态重定位方式,即作业或进程一旦进入主存,就一直等到它运行结束后才能释放主存。
缺点:
- 不支持多道程序
- 主存利用率不高
- 程序的运行收主存容量限制
单一连续内存管理的存储保护就比较好做,可以自动地址修改成用户区的地址。还有界限寄存器,划分系统区和用户区。
分区内存分配
把内存空间用户区以静态方式或者动态方式划分成若干连续的内存区域,每个内存分区可装入一道作业,故运行多道程序同时装入内存的不同分区并支持多道程序的并发执行。
(1)固定分区分配
预先 将可分配的主存储器空间分成若干个连续区域(分区),每个分区的大小可以相同也可以不同。但是分区的大小固定不变,每个分区只能装一个作业,如果有空闲区,则分配给进程。
分配通过设置内存分配表,内存分配简单,但是内存利用率不高。
(2)可变内存分配
基本思想:内存不是预先划分好的,而是当作业装入时,根据作业的需求和内存空间的使用情况来决定是否分配。如果有足够的空间,则按需分割一部分分区给该进程,否则等待。
内存管理:设置内存空闲块表——记录空闲块的起始地址和长度
内存分配:动态分配
内存回收:当某一块归还后,前后空间合并,修改内存空闲块表
分区分配中的数据结构:
- 空闲分区链:
2.分区分配表:
分区分配操作:
-
分配内存:
-
回收内存:如图:
a:将F1的表长度改为F1和回收区长度之和。
b:将F2的起始地址改为回收区地址,长度改为两区长度之和。
c:将F2表项删去,F1的长度改为三区长度之和。
若回收区上下都是占有区,则新建表项,起始地址为回收区起始地址,长度为回收区长度。
-
分配算法:
- 1)最佳适应算法:接到内存申请时,找到一个不小于请求的最小空快进程分配。
最作业选择分区时总是寻找其大小最接近与罪业所要求的存储区域,该算法要求分区的数据结构按空闲分区大小顺序排列或链接,方便查找,最佳适应按照从小到大递增分布。
特点:用最小空间满足要求 - 2)最坏适应算法:接到内存申请时,在空闲块表中找到一个不小于请求的最大空块进行分配。
特点:当分割后空闲块仍为较大分块需要空闲区按由大到小递减顺序排列。 - 3)首次适应法:为作业选择分区时总是按地址从高到低搜索,只要找到可以容纳该作业的空白块,就把该空白块分配给该作业。
- 4)循环首次适应算法:类似首次适应算法分区时,总是从上次查找结束的地方开始,使得内存空间的利用更加均衡。
碎片问题:
经过一段时间的分配和回收之后,内存中会出现很小的空闲块,这些空闲块也不满足内存需求,被称为碎片,这些碎片会造成内存的浪费。
为了解决这一问题,可以采用紧凑技术,通过内存移动将空闲块合并成一个大的空闲区域。问题:开销过大,不好把握移动的时机。
(3) 可重定位分区分配
优点:消除由可变分区带来的“外零头”,消除内存碎片,提高内存利用率。
缺点:提高硬件成本,紧凑技术花费CPU时间。
分页内存管理
分页内存管理使得数据可以离散的存储在内存上,有效提高了内存的利用率
1.页面与物理块:
在分页内存管理中,内存空间被划分成一系列大小相同的内存区域,称之为物理块(也成为内存分页或页框)。相应的,、进程的逻辑地址空间也被划分成与所装入系统物理块大小相同的若干区域,称之为页面或分页。页面的大小取决于物理块大小。(物理块一般取2的幂次)
2.页表:
- 内存页表:给出物理块的使用情况和保护设置。
- 进程页表:每个进程有独立的进程页表来描述进程和物理块之间的对应关系。
3.地址结构:
逻辑地址结构由页号和页内偏移地址组成。
页号 = INT[逻辑地址/页面大小]
页内偏移量 = 逻辑地址 MOD 页面大小
4.内存的分配和回收:
使用位图法,找一个m*n的矩阵,里面每一块代表一个内存块,若是1则为已分配,0表示空闲。
分配步骤:
1. 检查系统(位图)内空闲块数是否满足进程的需求,满足进入第二步否则等待
2. 顺序扫描位图,找到所有的空闲块,存入Map[i,j]
3. 将找到的Map[i,j]改成与之对应的物理块号,例Map[2,3],在列数为16的位图(从一开始),物理块号为(2-1)*16+3=19
4. 设置进程页表对应项,将位图里对应的块修改为1
回收类似。
5.地址变换机构:
基本的地址变换机构:
因为页表随着发展变得很大,所以设置一个页表寄存器,将页表存入主存,页表寄存器内是页表起始地址和页表的长度。将给的地址中的页号加上页表起始地址找到页表中页号,在找到对应块号,再用块号和给的地址组合生成物理地址。
带快表的地址变换机构:
因为基本的地址变换机构每访问一次数据,都要访问两次内存,第一次访问内存中的页表,第二次访问内存处理数据,就影响速度。
**所以增加并行查询能力的TLB(Translation Lookaside Buffer)高速缓冲储存器,用来存最近访问过的页表项,当给定页号时,可以现在TLB中找,找不到再去页表找。好像cache,一个东西
6.两级和多级页表:
因为现代计算机支持的逻辑地址空间非常大,会造成页表过大,这样查找非常麻烦,所以设置二级和多级页表。
例如32位,若页面大小为4KB,则每个进程页表的页表项可达1M个,若页表项大小为4B, 则每个进程仅页表就需要4MB的内存空间,且要求是连续的空间,这不合理。
反置页表:
分段内存管理
主要是为了满足用户在编程和使用上的多方面的需求
好处:
- 方便编程:用户的作业一般都是按段分的,程序的逻辑结构一般也是按照段来分,
- 信息共享:通常,在实现程序和数据共享时,都是以信息的逻辑单位为基础的。
- 信息保护:在多道程序的环境下,为了防止其他程序对该程序的数据有意无意地破坏,采取的保护措施一般也是对信息的逻辑单位进行保护。
- 动态链接:
- 动态增长
分段:
程序的地址空间被划分为多个逻辑分段,每个分段有自己的逻辑信息。
段表:
段表记录了段号,段长和基址
因为段的项按段号顺序排列,所以在段表中没有显示给出。
地址转换过程:
同样也有快表TLB的存在
分段和分页的区别:
- 页是信息的物理单位,段则是信息的逻辑单位。
- 页的大小固定由系统决定,而段的长度不固定。
- 分页的作业地址空间是一维的,而分段的作业地址空间是二维的。
分段的缺点是:产生碎片。
段页存储管理:
结合分段和分页的优点。克服两者的缺点。
基本思想:
用户程序划分:按段式划分(对于用户来讲,按段的逻辑关系进行划分;对系统来讲,按页划分每一段)。
内存划分:按页式存储管理方案
内存分配:以页为单位进程分配
除了对程序的分段是按照分段,每个段有自己的页表,其余的控制都是用页式存储管理。
虚拟存储
引入:覆盖与交换技术
-
覆盖技术:一个程序无需所有指令和数据装入内存,把程序划分成若干功能上相互独立的段,并让那些不会同时执行的程序段共享一块内存,用的时候可以将用的程序覆盖入对应的内存。
如子程序A1,A2,A3共享一段120KB 的内存,需要用谁就调用进去把原来的覆盖掉。
-
对换技术:就是把内存中用不到的程序和数据或运行不了的资源进程调到外存,把可以运行的和程序要用的资源调入内存。
虚拟存储器:
问题的起因:
- 因为运行的程序大于内存
- 程序暂时不执行或运行完是否还要占用内存
于是操作系统把程序当前使用的部分保留在内存,二八其他部分保存在磁盘上,并在需要时进行动态替换。并支持多道程序设计技术。
程序的局部性原理:
- 时间局部性:当前执行的指令不久的将来可能还要执行。(循环)
- 空间局部性:若某一储存单元被使用,则某一时间内,相邻的储存单元也可能被使用。(数组)
虚拟存储器对用户而言可以提供比实存更大的地址空间。目的是提高内存利用率。
虚拟存储器的特性: ———————对应常观存储器:
- 离散性:———————————— 1.连续性
- 交换性:———————————— 2.驻留性
- 多次性:———————————— 3.一次性
- 虚拟性:
虚拟存储器的最大容量也是受到计算机地址结构决定。
为了实现虚拟存储不得不引入请求调页和请求调段功能。
请求分页存储管理
与分页不同,请求式分页存储系统在开始运行前并不装入全部页面,而是装入一个或零个页面,根据运行的需要,动态装入其他页面;当内存满的时候,根据算法进行置换。
若发现所需要的页不在内存时,启动缺页中断,相应的中断处理子程序将所缺的页面调入主存,若主存有空闲块,则调入,若内存满了,则执行页面置换算法。
缺页中断:
- 保护CPU现场
- 分析中断原因
- 转入缺页中断处理子程序
- 恢复现场
页面置换算法:
- 最佳置换算法:选择永不使用或在最长时间内不再被访问的页面淘汰出内存,这只是一种理论上的算法,因为页面访问的预测很难做到,该算法一般用来评价其他算法。
- FIFO算法:最先进入的页面最先被置换,该算法实现最简单,但是不符合进程实际规律,一般不使用。
- 最久未使用算法:选择内存中最久未使用的页面,性能比较好,实现稍微复杂一点,需要稍微多一点硬件,如移位寄存器或栈。
- Clock置换算法:每个页面设置一个访问位,若为1,则最近被访问过。通过指针向下走,若访问位为1,则该为0,移动至下一位,若为0,则置换该页。
改进型的Clock算法,设置访问位A和修改位M。
分三步:
1. 第一步:第一轮扫描寻找A=0,M=0的页面,若没找到,也不改变访问位A。
2. 第二步:寻找A=0,M=1的页面,将所有扫描过的页面的访问位都置0。
3. 若第二步失败,直接将所有访问位置0,指针回到开始重新找。 - 最少使用置换算法:每个页面放一个移位寄存器来记录被访问的频率。该算法不能真实反映访问情况,不用。
- 页面缓冲算法:设立空闲页面链表和已修改页面链表。采用可变分配和和基于先进先出的局部置换策略,规定被淘汰页先不做物理移动,先依据是否修改分别挂到空闲页链表或者已修改链表的末尾。当已经修改链表达到一定数值时,一起将已修改页面写回磁盘,这样有效减少磁盘I/O的操作次数。
请求分段储存管理
与请求分页类似,也有缺段中断管理。