3. 内存管理
3.1 内存管理(上)
3.1.1 内存管理的基础知识
3.1.1.1 内存的基本认识
内存可存放数据。程序执行前需要先放到内存中才能被CPU处理——缓和CPU与硬盘之间的速度矛盾
思考:在多道程序环境下,系统中会有多个程序并发执行,也就是说会有多个程序的数据需要同时放到内存中。那么,如何区分各个程序
的数据是放在什么地方的呢?
方案:给内存的存储单元编地址
3.1.1.2 进程运行的基本原理
指令的工作原理
指令的工作基于“地址”。每个地址对应一个数据的存储单元。
从X=X+1大致看一下指令的执行过程
可见,我们写的代码要翻译成CPU能识别的指令。这些指令会告诉CPU应该去内存的哪个地址读/写数据,这个数据应该做什么样的处、
理。在这个例子中,我们默认让这个进程的相关内容从地址#0开始连续存放,指令中的地址参数直接给出了变量 x 的实际存放地址(物
理地址)。
逻辑地址和物理地址
装入的三种方式— 绝对装入
装入的三种方式—可重定位装入
装入的三种方式—动态运行时装入
从写程序到程序运行
链接的三种方式
静态链接
在程序运行之前,先将各目标模块及它们所需的库函数连接成一个完整的可执行文件(装入模块),之后不再拆开。
装入时动态链接
将各目标模块装入内存时,边装入边链接的链接方式。
运行时动态链接
在程序执行中需要该目标模块时,才对它进行链接。其优点是便于修改和更新,便于实现对目标模块的共享。
3.1.1.3 内存管理的概念
内存空间的分配与回收
内存空间的扩展
地址转换
内存保护
3.1.2 覆盖和交换
对于内存空间的扩充,我们常用到的技术就是覆盖技术和交换技术
3.1.2.1 覆盖技术
3.1.2.2 交换技术
3.1.3 连续分配管理方式
对于内存空间的分配和回收,我们可分为连续分配管理方式和非连续分配管理方式。
而对于连续分配管理方式又可分为单一连续分配、固定分区分配、动态分区分配。
连续分配:指为用户进程分配的必须是一个连续的内存空间。
3.1.3.1 单一连续分配
3.1.3.2 固定分区分配
3.1.3.3 动态分区分配
使用的数据结构
如何分配
如何回收
内部碎片与外部碎片
3.1.3.4 动态分区分配算法
动态分区分配算法:在动态分区分配方式中, 当很多个空闲分区都能满足需求时,应该选择哪个分区进行分配?
首次适应算法
最佳适应算法
最坏适应算法
邻近适应算法
3.1.3.5 四种算法归纳比较
3.2 内存管理(中)
这部分为非连续分配管理方式
3.2.1 基本分页存储管理方式
3.2.1.1 分页存储的基本概念与思想
基本思想
重要概念
如何实现地址转换
将进程地址空间分页之后,操作系统该如何实现逻辑地址到物理地址的转换?
如何计算页号和页偏移量
为什么页面大小一般设为2的整数次幂?
分页存储的逻辑结构
如何知道页面在内存中的起始地址?
这里引入一个重要的数据结构—页表
为了能知道进程的每个页面在内存中存放的位置,操作系统要为每个进程建立一张页表。
页表通常存在PCB(进程控制块)中
3.2.1.2 基本地址变换机构
基本地址变换机构可以借助进程的页表将逻辑地址转换为物理地址。
通常会在系统中设置一个页表寄存器(PTR),存放页表在内存中的起始地址F 和页表长度M。
进程未执行时,页表的始址和页表长度放在**进程控制块(PCB)**中,当进程被调度时,操作系统内核会把它们放到页表寄存器中。
注意:页面大小是2的整数幂
设页面大小为L,逻辑地址A到物理地址E的变换过程如下:
总体流程
-
计算页号P和页内偏移量W( 如果用十进制数手算,则 P=A/L,W=A%L;但是在计算机实际运行时,逻辑地址结构是固定不变的,因
此计算机硬件可以更快地得到二进制表示的页号、页内偏移量)
-
比较页号P 和页表长度M,若 P≥M,则产生越界中断,否则继续执行。(注意:页号是从0开始的,而页表长度至少是1,因此 P=M
时也会越界)
-
页表中页号P对应的页表项地址 = 页表起始地址F + 页号P * 页表项长度,取出该页表项内容b,即为内存块号。(注意区分页表项长
度、页表长度、页面大小的区别。页表长度指的是这个页表中总共有几个页表项,即总共有几个页;页表项长度指的是每个页表项占
多大的存储空间;页面大小指的是一个页面占多大的存储空间)
-
计算 E = b * L + W,用得到的物理地址E 去访存。(如果内存块号、页面偏移量是用二进制表示的,那么把二者拼接起来就是最终的
物理地址了)
一道例题来再次说明
对页表项大小的进一步探讨
3.2.1.3 快表的地址变换机构
快表,又称联想寄存器(TLB, translation lookaside buffer ),是一种访问速度比内存快很多的高速缓存(TLB不是内存!),用来存
放最近访问的页表项的副本,可以加速地址变换的速度。与此对应,内存中的页表常称为慢表。
快表是基本地址变换机构的改进版本。
引入快表后,地址的变换过程
-
CPU给出逻辑地址,由某个硬件算得页号、页内偏移量,将页号与快表中的所有页号进行比较。
-
如果找到匹配的页号,说明要访问的页表项在快表中有副本,则直接从中取出该页对应的内存块号,再将内存块号与页内偏移量拼接
形成物理地址,最后,访问该物理地址对应的内存单元。因此,若快表命中,则访问某个逻辑地址仅需一次访存即可。
-
如果没有找到匹配的页号,则需要访问内存中的页表,找到对应页表项,得到页面存放的内存块号,再将内存块号与页内偏移量拼接
形成物理地址,最后,访问该物理地址对应的内存单元。因此,若快表未命中,则访问某个逻辑地址需要两次访存(注意:在找到页
表项后,应同时将其存入快表,以便后面可能的再次访问。但若快表已满,则必须按照一定的算法对旧的页表项进行替换)
由于查询快表的速度比查询页表的速度快很多,因此只要快表命中,就可以节省很多时间。因为局部性原理,一般来说快表的命中率
可以达到 90% 以上。
例:某系统使用基本分页存储管理,并采用了具有快表的地址变换机构。访问一次快表耗时 1us,访问一次内存耗时 100us。若快表
的命中率为 90%,那么访问一个逻辑地址的平均耗时是多少?
(1+100) * 0.9 + (1+100+100) * 0.1 = 111 us
有的系统支持快表和慢表同时查找,如果是这样,平均耗时应该是 (1+100) * 0.9 + (100+100) * 0.1 =110.9 us
若未采用快表机制,则访问一个逻辑地址需要 100+100 = 200us。显然,引入快表机制后,访问一个逻辑地址的速度快多了。
思考,能否把整个页表都放在 TLB 中?
局部性原理
总结
3.2.1.4 两级页表
单级页表存在的问题
根据局部性原理可知,很多时候,进程在一段时间内只需要访问某几个页面就可以正常运行了。因此没有必要让整个页表都常驻内存。
问题一:页表必须连续存放,因此当页表很大时,需要占用很多个连续的页框。
解决方法:把页表再分页并离散存储,然后再建立一张页表记录页表各个部分的存放位置,称为页目录表,或称外层页表,或称顶层页表
两级页表的原理、地址结构
如何实现地址变换
问题二:没有必要让整个页表常驻内存,因为进程在一段时间内可能只需要访问某几个特定的页面。
解决方法:可以在需要访问页面时才把页面调入内存(虚拟存储技术)。可以在页表项中增加一个标志位,用于表示该页面是否已经调入
内存
3.3 内存管理(下)
3.3.1 基本分段存储管理方式
基本分段存储管理与“分页”最大的区别就是——离散分配时所分配地址空间的基本单位不同
3.3.1.1 分段
进程的地址空间:按照程序自身的逻辑关系划分为若干个段,每个段都有一个段名(在低级语言中,程序员使用段名来编程),每段从0
开始编址
内存分配规则:以段为单位进行分配,每个段在内存中占据连续空间,但各段之间可以不相邻。
分段的逻辑地址
3.3.1.2 段表
3.3.1.3 地址变换
3.3.1.4 分段、分页管理的对比
3.3.2 段页式管理方式
3.3.2.1 分页、分段的优缺点分析
3.3.2.1 段页式管理
段页式管理的逻辑地址结构
段表与页表
3.4 虚拟内存管理(上)
3.4.1 虚拟内存的基本概念
3.4.1.1 传统存储管理方式的特征、缺点
3.4.1.2 局部性原理
3.4.1.3 虚拟内存的定义和特征
虚拟内存有一下三个主要特征:
多次性:无需在作业运行时一次性全部装入内存,而是允许被分成多次调入内存。
对换性:在作业运行时无需一直常驻内存,而是允许在作业运行过程中,将作业换入、换出。
虚拟性:从逻辑上扩充了内存的容量,使用户看到的内存容量,远大于实际的容量。
如何实现虚拟内存技术
虚拟内存技术,允许一个作业分多次调入内存。如果采用连续分配方式,会不方便实现。因此,虚拟内存的实现需要建立在离散分配的内
存管理方式基础上。
3.4.2 请求分页管理方式
3.4.2.1 页表机制
3.4.2.2 缺页中断机构
3.4.2.3 地址变换机构
3.5 虚拟内存管理(下)
3.5.1 页面置换算法
3.5.1.1 最佳置换算法( OPT )
最佳置换算法可以保证最低的缺页率,但实际上,只有在进程执行的过程中才能知道接下来会访问到的是哪个页面。操作系统无法提前预
判页面访问序列。因此,最佳置换算法是无法实现的。
3.5.1.2 先进先出置换算法( FIFO )
3.5.1.3 最近最久未使用置换算法( LRU )
3.5.1.4 时钟置换算法( CLOCK )
3.5.1.5 改进型的时钟置换算法
只需一轮:
需要两轮:
需要三轮
需要四轮: