IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 嵌入式 -> 第三章:内存管理 -> 正文阅读

[嵌入式]第三章:内存管理

目录

一:内存管理概念

基础知识

内存管理的概念

覆盖与交换

内存空间的分配和回收

动态分区分配算法

基本分页存储管理的基本概念(非连续分配)

基本地址变换机构

具有快表的地址变换机构

两级页表

基本分段存储方式

段页式管理方式

二:虚拟内存

虚拟内存管理

请求分页管理方式:页表机制、缺页中断机构、地址变换机构

页面置换算法

页面分配策略


一:内存管理概念

  • 基础知识

逻辑地址:CPU生成的地址。是内部和编程使用的,并不唯一。

物理地址:加载到内存地址寄存器中的地址,内存单元真正地址。

装入的三种方式:

绝对装入:在编译时,如果知道程序将放到内存中的哪个位置,编译程序将产生绝对地址的目标代码。装入程序按照装入模块中的地址,将程序和数据装入内存。(只适用于单道程序环境)

静态重定位:又称可重定位装入。编译、链接后的装入模块的地址都是从0开始,指令中使用的地址、数据存放的地址都是相对于起始地址而言的逻辑地址。可根据内存的当前情况,将装入模块装入内存的适当位置。装入时对地址进行“重定位”,将逻辑地址变换为物理地址。(特点是在一个作业装入内存时,必须分配其要求的全部内存空间,若没有足够内寸,就不能装入,作业一旦进入内存,运行期间不能再移动,也不能在申请内存空间)

动态重定位:又称动态运行时装入。编译链接后的装入模块的地址都是从0开始的。装入程序把装入模块装入内存后,并不会立即把逻辑地址转换为物理地址,而是把地址转换推迟到程序真正要执行时才运行。这种方式需要一个重定位寄存器支持。

链接的三种方式:

静态链接:在程序运行前,先将各目标模块及它们所需的库函数连接成一个完整的可执行模块,之后不再拆开。

装入时动态链接:将各目标模块装入内存,边装入边链接的链接方式。

运行时动态链接:在程序执行中需要该目标模块时,才对它进行链接。优点是便于修改和更新,便于实现对目标模块的共享。

  • 内存管理的概念

内存空间的分配和回收;内存空间的扩充;地址转换;存储保护。

存储保护:

法一:在CPU设置一对上下限寄存器,存放上下限地址。进程的指令要访问某个地址时,检查是否越界。

法二:采用重定位寄存器(基址寄存器)和界地址寄存器(限长寄存器)进行越界检查。重定位寄存器中存放的是进程的起始物理地址。界地址寄存器中存放的是进程的最大逻辑地址。

  • 覆盖与交换

覆盖技术思想:将程序分为多个段(多个模块)。常用的段常驻内存,不常用的段在需要时调入内存。内存分为一个“固定区(运行过程中不会被调入调出)”和若干个“覆盖区(会根据需要调入调出)”。

必须由程序员声明覆盖结构,操作系统完成自动覆盖。缺点:对用户不透明,增加了用户编程负担。

交换技术思想:内存空间紧张时,系统将内存中某些进程暂时调出外存,把外存中某些已具备运行条件的进程换入内存。

具有对换功能的操作系统通常把磁盘分为文件区和对换区。

交换通常在许多进程运行且内存吃紧时进行,而系统负荷降低就暂停。

优先换出阻塞进程;可换出优先级低的进程;为了防止优先级低的进程在被调入内存后很快又被换出,有的系统还会考虑进程在内存的驻留时间。

  • 内存空间的分配和回收

连续分配管理方式:

单一连续分配方式:内存被分为系统区和用户区。系统区通常位于内存的低地址部分,用于存放操作系统相关数据;用户区用于存放用户进程相关数据。内存中只能有一道用户程序。(优点:实现简单;无外部碎片;可以采用覆盖技术扩充内存;不一定需要采取内存保护)(缺点:只能用于单用户、单任务的操作系统中;有内部碎片;存储器利用率极低)

固定分区分配:将整个用户空间划分为若干个固定大小(分区大小可相等可不等[分区说明表])的分区,每个分区只装入一道作业。(优点:实现简单,无外部碎片)(缺点:当用户程序太大,可能所有的分区都不能满足要求,此时不得不采用覆盖技术来解决,但这又会降低性能;会产生内部碎片,内存利用率低)

动态分区分配:(可变分区匹配)不会预先划分内存分区,在进程装入内存时,根据进程的大小动态的建立分区。系统通常使用:空闲分区表[每个空闲分区对应一个表项,表项中含有分区号、分区大小、分区起始地址等信息]、空闲分区链[每个分区的起始部分和末尾部分分别设置前向指针和后向指针。起始部分处还可记录分区大小等信息]记录内存的使用情况。支持多道程序,在进程装入内存时,根据进程的大小动态的建立分区,无内部碎片,有外部碎片

  • 动态分区分配算法

首次适应FirstFit:(效果最好)从低地址开始查找,找到第一个能满足大小的空闲分区。

最佳适应BestFit:空闲分区按容量递增次序链接,每次分配内存时顺序查找,找到大小能满足要求的第一个空闲分区。(缺点:最后会产生很多外部碎片)

最坏适应WorstFit:按容量递减次序排序,顺序查找找到满足的第一个空闲分区。(缺点:如果之后有“大进程”到达,就没有内存分区可用)

邻近适应NextFit:按地址递增排列成循环链表,从上次结束的时候开始查找

算法

思想

排列顺序

优点

缺点

首次适应

从头到尾找

地址递增

综合性能最好,算法开销小,回收分区后一般不需要对空闲分区队列重新排序

最佳适应

优先更小的

容量递增

会有更多大分区保留

外部碎片,算法开销大,回收分区后可能需要重新排序

最坏适应

优先大的

容量递减

减少小碎片

算法开销大、不利于大进程

邻近适应

首次适应从上次结束位置开始查找

地址递增

算法开销小

会使高地址的大分区也被用完

  • 基本分页存储管理的基本概念(非连续分配)

将内存空间分为一个个大小相等的分区,每个分区就是一个“页框”(页帧、内存块、物理块),每个页框都有一个编号,“页框号”(内存块号、页帧号、物理块号)从0开始。

将用户进程的地址空间也分为与页框大小相等的一个个区域,称为“”(页面),每个页面也有一个编号,页号,从0开始。

如何实现地址转换

1.算出逻辑地址对应的页号;

2.知道该页号对应页面在内存中的起始地址;

3.算出逻辑地址在页面当中的“偏移量”;

4.物理地址=页面始址+页内偏移量。

页号=逻辑地址/页面长度(取整)

页内偏移量=逻辑地址%页面长度(取余)

页面大小为2的整数幂时,可以用移位计算。

页表:记录每个页面在内存的存放位置。一个进程对应一张页表,每一页对应一个页表项,页表记录进程页面和实际存放的内存块间的对应关系。(页表的页号是隐含的,只需要知道页表存放起始地址和页表项长度,就可找到各个页号对应的页表项存放位置)

  • 基本地址变换机构

通常会在系统中设置一个页表寄存器(PTR),存放页表在内存中的起始地址F和页表长度M。进程未执行时,页表的始址和页表长度放在进程控制块(PCB)中,当进程被调度时,操作系统内核会把它们放到页表寄存器中。

1.根据逻辑地址计算页号、页内偏移量;

2.判断页号是否越界;

3.查询页表、找到也好对应的页表项,确定页面存放的内存块号。

4.用内存块号和页内偏移量得到物理地址;

5.访问目标内存单元。

理论上,页表项长度为3B即可表示内存块号的范围,但为了方便页表查询,会让一个页表项占更多的字节,使得每个页面恰好可以装下整数个页表项。

第一次访问内存:查页表;第二次:访问目标内存单元。

  • 具有快表的地址变换机构

时间局部性:如果执行了程序中的某条指令,那么不久后这条指令很有可能再次执行,如果某个数据被访问过,不久之后该数据很有可能再次被访问。

空间局部性:一旦程序访问了某个存储单元,在不久之后,其附近的存储单元也很有可能被访问。

快表,又称联想寄存器(TLB),是一种访问速度比内存快很多的高速缓冲存储器,用来存放当前访问的若干页表项,以加速地址变换的过程。内存中的页表常称为慢表

引入快表后,地址变换过程

1.CPU给出逻辑地址,有某个硬件算得页号、页内偏移量,将页号与快表中的所有页号进行比较。

2.如果找到匹配的页号,说明要访问的页表项在快表中有副本,直接从中取出该页对应的内存块号。最后访问该物理地址对应的内存单元。若块表命中,则只需一次访存。

3.如果没有找到匹配的页号,需要访问内存中的页表,找到对应页表项,得到页面存放的内存块号,访问物理地址对应的内存单元。若未命中,则需要进行两次访存。

  • 两级页表

单级页表存在的问题:页表必须连续存放,当页表很大时,需要占用很多个连续的页框。没有必要让整个页表常驻内存,因为进程在一段时间内可能只需要访问某几个特定的页面。

解决方法:为离散分配的页表再建立一张页表,称为页目录表。(外层页表/顶层页表)

两级页表地址变换

1.按照地址结构将逻辑地址拆分成三部分;

2.从PCB中读出页目录表始址,再根据一级页号查页目录表,找到下一级页表在内存中的存放位置;

3.根据二级页号查表,找到最终想访问的内存块号;

4.结合页内偏移量得到物理地址。

需要注意的细节

1.若采用多级页表机制,各级页表大小不能超过一个页面

2.两级页表访存次数分析:第一次:访问内存中的页目录表;第二次:访问内存中的二级页表;第三次:访问目标内存单元。

  • 基本分段存储方式

进程的地址空间:按照程序自身的逻辑关系划分为若干个段,每个段都有一个段名(在低级语言中,程序员使用段名来编程)每段从0开始编址。

内存分配规则:以段为单位进行分配,每个段在内存中占据连续空间,但各段之间可以不相邻。

分段系统的逻辑地址结构由段号(段名)和段内地址(段内偏移量)所组成。

段号的位数决定了每个进程最多可以分几个段,段内地址位数决定了每个段的最大长度是多少。

段表:1.每个段对应一个段表项,其中记录了该段在内存中的起始位置(基址)和段的长度。

2.各个段表项的长度是相同的。(段号16位,段内地址16位)

段表寄存器:存放段表始址F+段表长度M

1.根据逻辑地址得到段号、段内地址;

2.判断段号是否越界;

3.查询段表,找到对应的段表项,段表项的存放地址为F+S*段表项长度;

4.检查段内地址是否超过段长;

5.计算物理地址;

6.访问物理地址。

分段、分页管理的对比

页是信息的物理单位。分页的主要目的是为了实现离散分配,提高内存利用率。分页仅仅是系统管理上的需要,完全是系统行为,对用户不可见。

段是信息的逻辑单位。分段的主要目的是更好的满足用户需求,一个段通常包含一组属于一个逻辑模块的信息。分段对用户是可见的,用户编程需要显式地给出段名。

分页的用户进程地址空间是一维的,程序员只需给出一个记忆符即可表示一个地址。

分段的用户进程地址空间是二维的,程序员在标识一个地址时,既要给出段名,也要给出段内地址。

分段比分页更容易实现信息的共享和保护

不能被修改的代码称为纯代码或可重入代码(不属于临界资源),这样的代码是可以共享的。可修改的是不能共享的。

分页:第一次访存---查内存中的页表,第二次访存---访问目标内存单元。两次。

分段:第一次访存---查内存中的段表,第二次访存---访问目标内存单元。两次。

  • 段页式管理方式

分页、分段管理方式中最大优缺点

优点

缺点

分页管理

内存空间利用率高,不会产生外部碎片,只会有少量的页内碎片

不方便按照逻辑模块实现信息的共享和保护

分段管理

很方便按照逻辑模块实现信息的共享和保护

如果段长过大,为其分配很大的连续空间会很不方便。另外,段式管理会产生外部碎片

段页式管理:将进程按逻辑模块分段,再将各段分页。

将地址空间按照程序自身的逻辑关系划分为若干个段,再将各段分为大小相等的页面。

将内存空间分为与页面大小相等的一个个内存块,系统以块为单位为进程分配内存。

每个段对应一个段表项,每个段表项由段号、页表长度、页表存放块号(页表起始地址)组成。每个段表项相等,段号是隐含的。

进程上处理机之前,从PCB中读取段表始址、段表长度。

逻辑地址结构:段号、页号、页内偏移量

地址转换

  1. 根据逻辑地址得到段号、页号、页内偏移量;
  2. 判断段号是否越界;
  3. 查询段表,找到对应的段表项,存放地址为始址+段号*段表项长度;
  4. 检查页号是否越界;
  5. 根据页表存放块号、页号查询页表,找到对应页表项;
  6. 根据内存块号、页内偏移量得到最终的物理地址;
  7. 访问目标内存单元。

第一次:查段表、第二次:查页表、第三次:访问目标单元。

可引入快表机构,以段号和页号为关键字查询块表,即可直接找到最终的目标页面存放的位置。引入快表后仅需一次访存。

二:虚拟内存

  • 虚拟内存管理

传统存储管理方式的特点/缺点:

一次性:作业必须一次性全部装入内存后才能开始运行。这会造成两个问题:1作业很大时,不能全部装入内存,导致大作业无法运行;2当大量作业要求运行时,由于内存无法容纳所有作业,因此只有少量作业能运行,导致多道程序并发度下降。

驻留性:一旦作业被装入内存,就会一直驻留在内存中,直至作业运行结束。事实上,在一个时间段内,只需要访问作业的一小部分即可正常运行,就导致内存中驻留大量、暂时用不到的数据,浪费了宝贵的内存资源。

高速缓冲技术:将近期会频繁访问的数据放到更高速的存储器中,暂时用不到的数据放在更低速存储器中。

易混知识点:

虚拟内存的最大容量是由计算机的地址结构(CPU寻址范围)确定的;虚拟内存的实际容量=min(内存和外存容量之和,CPU寻址范围)

虚拟内存有以下三个主要特征

多次性:无需在作业运行时一次性全部装入内存,而是允许被分成多次调入内存。

对换性:在作业运行时无需一直常驻内存,而是允许在内存运行过程中,将作业换入、换出。

虚拟性:从逻辑上扩充了内存的容量,使用户看到的内存容量,远大于实际的容量。

虚拟内存技术,允许一个作业多次调入内存,如果采用连续分配方式,会不方便实现。因此,虚拟内存的实现需要建立在离散分配的内存管理方式基础上。

虚拟内存的实现:请求分页存储管理;请求分段存储管理;请求段页式存储管理。

传统的非连续分配存储管理与虚拟内存实现的区别:

在程序运行过程中,当所访问的信息不在内存时,由操作系统负责将所需信息从外存调入内存,然后继续执行程序。(请求调页/段功能)

若内存空间不够,由操作系统负责将内存中暂时用不到的信息换出到外存。(页面置换或段置换功能)

请求分页存储管理与基本分页存储管理的主要区别:

在程序执行过程中,当所访问的信息不在内存时,由操作系统负责将所需信息从外存调入内存,然后继续执行程序。

若内存空间不够,由操作系统负责将内存中暂时用不到的信息换出到外存。

  • 请求分页管理方式:页表机制、缺页中断机构、地址变换机构

页号

内存块号

状态位

访问字段

修改位

外存地址

0

0

0

0

X

1

B

1

10

0

Y

2

C

1

6

1

z

状态位:是否已经调入。

访问字段:记录最近被访问的次数,或记录上次访问的时间,供置换算法选择换出页面时参考。

修改位:调入后是否被修改过。

外存地址:外存中的地址。

在请求分页系统中,每当要访问的页面不在内存时,便产生一个缺页中断,然后由操作系统的缺页中断处理程序处理中断。此时缺页的进程阻塞,放入阻塞队列,调页完成后再将其唤醒,放回就绪队列。

如果内存中有空闲块,则为进程分配一个空闲块,将所缺页面装入该块,并修改页表中相应的页表项。若没有空闲块,由页面置换算法选择一个页面淘汰,若该页面在内存期间被修改过,则要将其写回内存。

缺页中断是因为当前执行的指令想要访问的目标页面未调入内存而产生的,属于内中断。一条指令在执行期间,可能产生多次缺页中断。

新增步骤(请求调页、页面置换、需要修改请求页表中新增的表项

补充细节:

  1. 只有“写指令”才需要修改“修改位”。一般来说只需修改块表中的数据,只有要将快表项删除时才需要写回内存中的慢表。减少访存次数。
  2. 和普通中断处理一样,缺页中断需要保留CPU现场。
  3. 需要用某种“页面置换算法”来决定一个换出页面。
  4. 换入/换出页面都需要启动慢速的I/O操作,可见,如果换入/换出太频繁,会有很大开销。
  5. 页面调入内存后,需要修改慢表,同时也需要将快表项复制到快表中。
  • 页面置换算法

缺页率=缺页中断次数/访问页面次数

最佳置换算法(OPT):每次选择淘汰的页面将是以后永不使用,或是在最长时间内不再被访问,保证最低的缺页率。但实际上,操作系统是无法预测页面访问序列,因此,最佳置换算法是无法实现的。

先进先出置换算法(FIFO):每次选择最早进入内存的页面淘汰。把调入内存的页面根据调入的先后顺序排成一个队列,需要换出页面时选择队头页面即可。(Belady异常:当为进程分配的物理块数增加时,缺页次数不减反增的异常现象)只有FIFO有Belady异常。实现简单,但与实际运行时的规律不适应,算法性能差。

最近最久未使用置换算法(LRU):淘汰最近最久未使用的页面。实现需要专门的硬件支持,性能好,但是实现困难,开销大。

时钟置换算法(CLOCK):或称最近未用算法(NRU)。

简单的CLOCK算法实现方法:为每个页面设置一个访问位,再将内存中的页面都通过链接指针链接成一个循环队列。当某页被访问,访问位置为1,需要淘汰时,只检查访问位,0将页换出,1将1换为0,暂不换出,继续检查直到遇到0。(最多会经历两轮扫描)

改进型的时钟置换算法:淘汰没有修改过的页面。(访问位,修改位)

算法规则:将所有可能被置换的页面排成一个循环队列。

第一轮:从当前位置开始扫描到第一个(0,0)的帧用于置换。本轮不修改任何标志位。(没有访问和修改)

第二轮:第一轮失败,查找第一个(0,1)的帧用于置换。本轮将所有扫描过的访问位设为0。(没有访问,但修改过)

第三轮:第二轮失败,查找第一个(0,0)的帧用于置换。不修改任何标志位。(最近访问过,但是没有修改过)

第四轮:第三轮失败,查找第一个(0,1)的帧用于置换。(最近访问和修改过)

最多会进行四轮扫描。

算法规则

优缺点

OPT

优先淘汰最长时间内不会访问的页面

缺页率最小,性能最好;但无法实现

FIFO

优先淘汰最先进入内存的页面

实现简单,但性能很差,可能出现Belady异常

LRU

优先淘汰最近很久没访问的页面

性能很好,但需要硬件支持,算法开销大

CLOCK

循环扫描,优先淘汰没访问过的

实现简单,算法开销小;但未考虑页面是否修改过

改进型CLOCK

四轮

算法开销小,性能也不错

  • 页面分配策略

驻留集:指请求分页存储管理中给进程分配的物理块的集合。

固定分配:操作系统为每个进程分配一组固定数目的物理块,在进程运行期间不再改变,即驻留集大小不变。

可变分配:先为每个进程分配一定数目的物理块,在进程运行期间,可根据情况做适当的增加或减少。即驻留集大小可变。

局部置换:发生缺页时只能选进程自己的物理块进行置换。

全局置换:可将操作系统保留的空闲物理块分配给缺页进程,也可将别的进程持有的物理块置换到外存,再分配给缺页进程。

固定分配局部置换:缺点:很难在刚开始就确定应为每个进程分配多少个物理块才算合理。

可变分配全局置换:只要某进程发生缺页,就能获得新的物理块。若被选中调出的页的进程物理块会减少,缺页率会增加。

可变分配局部置换:刚开始为每个进程分配一定数量的物理块。缺页时只允许从该进程自己的物理块中选出一个换出外存。若在运行中频繁的缺页,系统会为该进程多分配几个物理块,直至缺页率到适当程度;反之,如果进程在运行中缺页率特别低,则可适当减少分配给该进程的物理块。

何时调入页面?

1.预调页策略:根据局部性原理,一次调入若干个相邻的页面可能比一次调入一个页面更高效。预测不久可能访问到的页面成功率只有50%,这种策略主要用于进程的 首次调入。

2.请求调页策略:运行期间发现缺页时才将所缺页面调入内存。这种策略调入的页面一定会被访问到,但由于每次只能调入一页,而每次调页都要磁盘I/O操作,因此I/O开销较大。

从何处调入页面?

1.系统拥有足够的对换区空间:页面的调入调出都是在内存与对换区之间进行,这样可以保证页面的调入调出速度很快。在金策哼给你运行前,需将进程相关的数据从文件区复制到对换区。

2.系统缺少足够的兑换区空间:凡是不会被修改的数据都直接从文件区调入,由于这些页面不会被修改,因此换出时不必写回磁盘,下次需要时再从文件区调入即可。对于可能被修改的部分,换出时需写回磁盘对换区,下次需要时再从对换区调入。

3.UNIX方式:运行之前进程有关的数据全部放在文件区,都可从文件区调入。若被使用过的页面需要调出,则写回对换区,下次需要时从对换区调入。

抖动现象:刚刚换出的页面马上又要换入内存,刚刚换入的页面马上又要换出外存,这种频繁的页面调度行为称为抖动,或颠簸。产生抖动的主要原因是进程频繁访问的页面数目高于可用的物理块数。

工作集:指在某段时间间隔内,进程实际访问页面的集合。

实际应用中,操作系统可以统计进程的工作集大小,根据工作集大小给进程分配若干内存块。一般来说,驻留集大小不能小于工作集大小,否则进程运行过程中将频繁缺页。

  嵌入式 最新文章
基于高精度单片机开发红外测温仪方案
89C51单片机与DAC0832
基于51单片机宠物自动投料喂食器控制系统仿
《痞子衡嵌入式半月刊》 第 68 期
多思计组实验实验七 简单模型机实验
CSC7720
启明智显分享| ESP32学习笔记参考--PWM(脉冲
STM32初探
STM32 总结
【STM32】CubeMX例程四---定时器中断(附工
上一篇文章      下一篇文章      查看所有文章
加:2022-01-25 10:45:17  更:2022-01-25 10:45:33 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 10:51:19-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码