操作系统 —— 2 内存管理

在这里插入图片描述
os被加载到操作系统后,会对整个计算机系统进行管理和控制,首先被管理和控制的就是内存,本章为如何管理物理内存
在这里插入图片描述

1 操作系统如何管理内存

1.1 计算机体系结构

在这里插入图片描述
计算机体系结构主要包括以下三大块:

  1. CPU:完成对整个程序或软件的执行的控制
  2. 内存:放置程序的代码和数据
  3. 外设:鼠标键盘等,都有各自的功能,来配合整个程序的执行

内存的层次结构:
在这里插入图片描述
从上到下CPU可以访问的数据包含:

  1. 寄存器和cache:os不能直接管理他们,因为他们在CPU内部,他们速度快,容量小,所以放置的数据和指令是有限的
  2. 主存(物理内存):与寄存器和cache相比,容量大速度慢,os相关的数据和代码放在这,可以存放多个程序同时运行(多道程序),但掉电就没了,所以需要永久保存的数据和代码需要放在硬盘,一加电就可以把数据和程序从硬盘读进来
  3. 硬盘(虚拟内存):掉电后存储的东西不消失,比主存速度更慢容量更大

所以越靠近CPU速度越快,存储容量越小
我们需要运行程序时数据的存取很快,存储空间很大,操作系统可以帮我们来完成这个需求

操作系统在内存管理方面需重点完成的:

  • 抽象:希望应用程序在内存中运行时在os的管理下不需要考虑底层的细节,包括不用考虑物理内存在什么地方,外设在什么地方等等,只需要访问一个连续的地址空间就可以了,这个连续的地址空间一般称为逻辑地址空间
  • 保护:内存中可以同时运行多个应用程序,某个程序可以会访问别的正在运行的程序的地址空间,我们需要一个机制来使得每个程序的地址空间相互隔离
  • 共享:使得不同进程能够安全可靠有效的进行数据传递
  • 虚拟:内存中放了多个程序可能就会出现不够用的情况,可以通过虚拟的方法使得程序有更多的地址空间,把需要使用的数据放到内存中,暂时不需要的放到硬盘上去来实现虚拟,这个过程对应用程序透明,但应用程序还可以使用到要用的数据

在这里插入图片描述
在上图os的管理下有4个程序放在内存中,正在占用CPU的是P1,P2、P3、P4处于等待状态
P1 P2 P3放在内存中,均可以轮流有效执行
P4因为需要等待的某事件需要过一会才能发生,且P1、P2、P3占据了大部分内存空间,所以数据没必要放到内存中去,因此把所有数据都放在了磁盘,当满足了某事件后,就可以回到内存去执行

为实现上述过程,就依赖于以下的方法:
在这里插入图片描述

1.2 地址空间与地址生成

运行程序需要的地址空间以及地址是如何生成的

1.2.1. 地址空间定义

在这里插入图片描述

物理地址空间——硬件支持的地址空间

  • 起始地址0,到地址MAXsys
  • 包括主存(内存条)和磁盘
  • 管理和控制由硬件完成

逻辑地址空间——一个运行的程序所看到的内存范围

  • 一维的线性地址空间,有了这个应用程序就可以很好的控制和访问数据
  • 起始地址0,到地址MAXprog

所有程序访问的逻辑地址空间最终都要落实到物理地址空间上,在程序中的地址从哪来?
给出的是在程序地址空间中的逻辑地址,然后由os协调放在主存还是硬盘中

1.2.2 地址生成

在这里插入图片描述
c程序中函数的位置和变量的名字就是一种逻辑地址
汇编语言已经更贴近机器语言了,但依然是用符号来代表变量和函数的名字,但也比机器语言更易于人阅读
机器语言:起始地址从0开始,会把变量符号名和函数符号名转变为逻辑地址

基于符号的地址空间(程序中的)找到具体逻辑地址(编译器等完成):

  • c程序->汇编语言->机器语言->(链接把多个程序变为一个单一的程序).exe file(可执行,放在硬盘中)->载入把放在硬盘的程序放在内存中运行(地址带有偏移量,依旧是逻辑地址)
  • 不需要os,全程是应用程序、编译器等等

在这里插入图片描述
逻辑地址到物理地址(os完成)

  • CPU方面:

    • 1、 运算器需要在逻辑地址的内存内容(ALU发出请求)
    • 2、内存管理单元寻找在逻辑地址和物理地址之间的映射(在MMU查找映射,找到物理地址就返回,未找到就会产生一个处理过程,然后去内存中找)
    • 3、控制器从总线给内存发送在物理地址的内存内容的请求
  • 内存方面

    • 4、内存发送物理地址内存的内容给CPU(主存会把内容通过主线传给CPU,CPU拿到这个指令后就可以开始执行了)
  • 操作系统方面

    • 建立逻辑地址和物理地址间的映射,可以放在主存中,由CPU进行缓存,从而加快映射过程

1.2.3 地址安全检查

操作系统要确保每个程序访问地址不受干扰,确保每个程序访问的地址空间是合法的。每次程序查这个map,看他要访问的逻辑地址是否满足这个限制,满足继续执行,不满足发出一个内存异常,与操作系统再来处理
在这里插入图片描述

1.3 连续内存分配:内存碎片与分区的动态分配

在这里插入图片描述

1.3.1 内存碎片问题

在这里插入图片描述
内存碎片:给一个运行的程序分配内存空间后,会出现一些无法被利用的空间,这些空间就是碎片

  • 外部碎片
    • 在分配单元的未使用内存
  • 内部碎片
    • 在分配单元的未使用内存(已经分配给了应用程序,但应用程序无法使用这些内存空间)

1.3.2 分区的动态分配

简单的内存管理方法:

  • 当一个程序准许运行在内存中时(程序从硬盘加载到内存中),分配一个连续的空间
  • 分配一个连续的内存区间给运行的程序以访问数据,要给这些数据一些存储空间

在这里插入图片描述

首次适配方法

在这里插入图片描述
基本原理 & 实现:

  • 简单实现
  • 需求
    • 按地址排序的空闲块列表
    • 分配需要寻找一个合适的分区
    • 重分配需要检查,看是否自由分区能合并于相邻的空闲分区(若有)
    • (从低地址开始找,找到一个合适的就使用,期间还要关注地址空间的回收,若回收区域与相邻区域均为空闲分区,则合并)

如需要400字节的内存,那么第一个空闲块1k就满足需求
优势

  • 简单
  • 易产生更大空闲块,向着地址空间的结尾(找到一个合适的就行,后面有更大的空间也不会因为被插入了个小的被浪费了)

劣势

  • 外部碎片(两块之间的小碎片不易被使用)
  • 不确定性(某些情况下会不适用)
最佳适配方法

在这里插入图片描述
基本原理 & 实现

  • 为了避免分隔大空闲块

  • 为了最小化外部碎片产生的尺寸

  • 需求:

    • 按空闲块尺寸大小排列的空闲块列表
    • 分配需要寻找一个合适的分区
    • 重分配需要搜索及合并于相邻的空闲分区(若有)
  • 优势

    • 当大部分小的内存分配时非常有效
    • 比较简单
  • 劣势

    • 把外部碎片拆的比较细,使得将来再利用这些外部碎片的可能性比较小
    • 重分配慢
    • 易产生很多没用的微小碎片(不怎么好)
最差适配方法

在这里插入图片描述
基本原理 & 实现

  • 为了避免有太多微小的碎片
  • 需求:
    • 按尺寸排列的空闲块列表
    • 分配很快(获得最大的分区)
    • 重分配需要合并于相邻的空闲分区(若有),然后调整空闲块列表

优势

  • 假如分配是中等尺寸效果最好(中大型地址空间最好)

劣势

  • 重分配慢
  • 外部碎片
  • 易于破碎大的空闲块,以致大分区无法被分配
  • (请求大的地址空间,分配后,再次请求大的就不容易被分配了)

没有一种算法是一直都使用的
接下来就要考虑如何更好的利用这些碎片化空间,使碎片减少或消失

1.4 连续内存分配:压缩式与交换式碎片整理

之前的方法都会产生内碎片和外碎片,有什么办法能够能弥补一下让碎片尽量少呢?碎片少就意味着空闲空间比较完整,大小比较大,便于后续的分配
使用压缩式碎片、交换式碎片方法

1.4.1 压缩式碎片整理

重置程序以合并空洞
要求所有程序是动态可重置
在这里插入图片描述
当有一个程序需要5个空闲块时,上左图不能满足,这时,就要考虑如何将程序拷贝,使每个程序之间不留内存空闲快,像右图一样
问题:
何时挪?

  • 程序运行时不能,因为万一一挪,就有可能导致后续程序请求地址时找不到
  • 程序等待某个事情没有占用CPU执时可以挪
    开销?
  • 频繁内存拷贝开销很大,甚至会影响整个系统的执行,纯靠软件完成开销较大
    能否改进这种靠软件来挪动运行程序在内存中地址的方法?

1.4.2 交换式碎片整理

运行程序需要更多的内存
抢占等待的程序 & 回收他们的内存
在这里插入图片描述
当P3正在运行,P1P2P4没有运行时,P3需要占用更多的空间,而此时,内存空间已经被P1P2P3P4占满了,靠挪空间已无效果,因为已经没有可用的内存空间了。
此时,可以将正在等待的P4程序的数据等拷贝到磁盘中,空出的3个内存块给P3使用。当P4执行时,P3可能就不需要那么多内存了,再把P4拷回来

问题:
把拿个程序拷出去?
什么时候换入换出?(程序较大时开销较大)
连续内存中换入换出的都是大的整个程序快,如何把这些换成小的块来换入换出话需要考虑
虚存管理时会涉及

1.5 非连续内存分配(分段)

在这里插入图片描述

1.5.1 为什么需要非连续内存分配

连续内存分配的缺点:

  • 分配给一个程序的物理内存是连续的
  • 内存利用率较低
  • 有外碎片、内碎片的问题

非连续分配的优点:

  • 一个程序的物理地址空间是非连续的
  • 更好的内存管理和利用:让运行的程序能够更好地做隔离和内存管理
  • 允许共享代码与数据(共享库等)
  • 支持动态加载和动态链接

非连续分配的缺点:

  • 如何建立虚拟地址和物理地址间的转换
    • 软件方案:开销大
    • 硬件方案:能否和计算机硬件结合,如和CPU里的关于内存管理的硬件组成部分结合在一起,共同完成硬件的非连续内存分配
    • 两种硬件方案:分段和分页

1.5.2 分段

在这里插入图片描述

程序的分段地址空间

在这里插入图片描述

如上图,计算机程序也是由各种各样的段组成的
比如在代码执行方面:有总程序、子程序、共享的库

数据也由各种各样的段组成,如有栈段、堆段、共享数据段
分段:更好的分离和管理
在这里插入图片描述
从程序的编写运行来说,逻辑地址空间是连续的
通过分段把逻辑地址分成几个段,然后映射到物理地址上去
物理地址空间是不连续的
中间需要映射机制
更有利于数据的共享和管理
又如:
在这里插入图片描述
逻辑地址分段映射到内存不同的段上去
用软件来处理映射开销较大,所以考虑使用硬件

分段寻址方案

在这里插入图片描述

在这里插入图片描述
虚拟地址空间映射到物理地址空间,物理地址空间由段组成
把逻辑地址分为2块,上半部分是段号,下半部分是段内偏移
通过段号来找到物理地址的段号,使用的是段表,里面存了映射关系,即逻辑地址段号和物理地址段好的对应关系
每个段大小是不一样的,需要了解它的起始地址和长度(这是段表里比较重要的2个信息)
段表的索引(index,哪一项的位置)由段号来决定
查到后的地址和长度限制,CPU查看要访问的是否符合这个限制,不符合,异常,符合,则把起始地址加上偏移量形成物理地址,CPU继续处理

(base和limit的箭头是不是画反了?)

段表由os在寻址之前建立,怎么建立段表与硬件有关

1.6 非连续内存分配(分页)

分段用的是比较少的,主要用分页
分页与分段相同点:

  • 分段需要段号和段内偏移
  • 分页也要页号和页内偏移

分页与分段区别:分段的段的尺寸是可变的,页的大小是不变的

1.6.1 分页地址空间

在这里插入图片描述

  • 划分物理内存至固定大小的帧(分成的每一个页)
    • 大小是2的幂,如 512,4096,8192
  • 划分逻辑地址空间至相同大小的页(页的大小)
    • 大小是2的幂,如 512,4096,8192
  • 建立方案 转换逻辑地址为物理地址(pages to frames)
    • 页表
    • MMU(CPU中)/TLB(快表完成对页表的缓存)

在这里插入图片描述
物理地址寻址方式:帧(Frame)

  • 物理内存被分隔成大小相等的帧
  • 一个内存物理地址是一个二元组(f,o)
    • f——帧号(F位,共有2F帧)
    • o——帧内偏移(S位,每帧有2S字节)
    • 物理地址=2s *f + o
    • 地址计算的实例
      • 16bit的地址空间,9bit(512byte)大小的页帧,物理地址=(3,6),求?
      • 9bit 用来表示帧内偏移,16bit-9bit=7bit用来表示帧号,则F=7,S=9
        在这里插入图片描述

在这里插入图片描述
逻辑地址寻址方式:页

  • 一个程序的逻辑地址空间被划分为大小相等的页
    • 页内偏移大小=帧内偏移的大小(每一个页的大小和每一帧的大小同)
    • 页号大小可能不等于帧号大小,即 f 可能不等于p
  • 一个逻辑地址是一个二元组(p,o)
    • p —— 页号(P位,2P个页)
    • o —— 页内偏移(S位,每页有2S字节)
    • 虚拟地址=2S *p+o

1.6.2 页寻址方案

程序在运行时无论运行指令还是要数据,都需要CPU去寻址知道指令或数据所在的位置
在这里插入图片描述

由逻辑地址中的页号作为一个索引去查页表(还需要知道从哪开始查,即页表基地址),查出该索引对应的页表项——帧号,把帧号和偏移量相加,得物理地址
页表由os建立

与段不同的地方:
页的逻辑地址和物理地址中的偏移量是一样的,所以不用像分段还要考虑大小不一致的问题

在这里插入图片描述
逻辑地址空间(连续)>物理地址空间(分散)
逻辑地址空间的内容物理地址空间不能全部装下,虚拟内存的时候会讲
逻辑地址连续,映射到物理地址后有可能分散到不同物理内存空间的页帧中,好处是有助于减少碎片

1.6.3 页表

概述

页表其实就是一个大数组
在这里插入图片描述
页表结构

  • 每个运行的程序都有一个页表
    • 属于程序运行状态,会动态变化
    • PTBR:页表基址寄存器
  • 页表的页表项除了帧号外,还有一些页表项的内容,用于特定的用途
    • 比如说,可以表示页表项是否是一个合法的页表项,即逻辑地址的页对应的物理地址的页是否存在,因为逻辑地址空间很大,物理地址空间比它小,那么一部分的逻辑地址就无法对应到物理地址上
    • 比如代表这一页读写属性,读过、写过、还是没读也没写过

页表其实是一个大数组,它的索引,即页号,对应的页表项的内容为帧号
过程:

  • CPU查出该页表的起始地址
  • 通过页号(page index)算出帧号
  • 帧号加偏移量得物理地址

在这里插入图片描述
上图实例:
逻辑地址:64KB
物理地址:32KB
所以不是所有的逻辑地址都有对应的物理地址,但是逻辑地址和物理地址的页内偏移是一样的,即页大小和帧大小一样,都是1024byte

逻辑地址(4,0)代表页号:4,偏移量:0,去查页表,从下往上数0,1,2,3,4第5个,它的resident bit(驻留位)为0(此逻辑地址在内存中无对应的物理地址)。内存访问异常,os继续处理,非法访问则将运行的程序杀死,(页表在程序运行前就已建立)
逻辑地址(3,1023)代表页号:3,偏移量:1023,去查页表,从下往上数0,1,2,3第4个,它的resident bit(驻留位)为1(此逻辑地址有对应的物理地址),取出帧号4与偏移量1023相加,得物理地址(4,1023)

在这里插入图片描述
分页机制的性能问题(速度和空间开销,希望速度快,空间开销小)

  • 页表可能非常大

    • 64位机器如果每页1024字节,那么一个页表的大小会是多少
      • 寻址空间:264
      • 一页大小:1024字节=1k=210
      • 一个页表的大小:264 /210 =254 (太大了)
    • 如果每个程序都有一个页表,那么n个将会有n个页表,很耗空间
  • 页表很大的话,CPU放不下,就要放在内存,所以就会访问2次内存

    • 问题:访问一个内存单元需要2次内存访问
      • 一次用于获取页表项(访问页表)
      • 一次用于访问数据(访问物理数据)
  • 如何处理?(提示:大部分的计算问题可通过某些方式解决)

    • 缓存(Caching):把最常用的内容放到离CPU最近的地方,如Cache,提升访问速度
    • 间接(Indirection)访问:把很大的空间拆成很小的空间
TLB(时间解决方法,缓存)

MMU中有TLB
在这里插入图片描述

得到的p先去查快表,若有,则取出f直接与o相加;若没有,再去查页表

TLB缺失会不会很大?通常而言,32位系统,1个快表4K,访问4K次才会导致TLB的缺失,通过某种机制使得这种缺失变小,这种机制就是写程序时尽量具有局部性,把平时的访问集中到一个区域

TLBmiss后,对于x86系统cpu是通过硬件来从页表中取出到TLB中,而有的是通过os来实现的

多级的页表(解决空间效率问题)
二级页表

在这里插入图片描述

把单一的table分为2块,逻辑地址的p分为p1(对应1级页表页号),p2(对应2级页表页号),使得对大地址的寻址变为n个小的页表的寻址,而不是对很大的页表进行寻址。
首先,对于一级页表,它的起始地址PTBR CPU知道,所以加上p1,得到页表项(存的是2级页表的起始地址),与p2相加,得二级页表的页表项,即f
之后,p2的页表项加上逻辑地址的偏移量得最终的物理地址

处理过程多了一次查找寻址处理(p2),但使得某一些不存在映射关系的页表项就不会占用内存了,如p1指向的某一页表项不存在(逻辑地址映射的在内存中的物理地址不存在导致的内存异常的情况),则不需要在查二级页表,节省了空间

多级页表

时间来换空间
64位可以做成五级页表
查这些页表所耗费的时间变长了,但是所使用的空间变少了
但是时间问题可以使用TLB解决
在这里插入图片描述

反向页表

逻辑地址空间越大,对应的页表越多
使得页表大小与逻辑地址无关,而与物理地址有关的方法:反向列表
在这里插入图片描述

帧号为索引,页表项为页号

使用页寄存器

在这里插入图片描述
问题:怎么根据页号找到页帧号?
在这里插入图片描述

在这里插入图片描述

基于关联内存(associative memory)的方案

硬件逻辑很复杂
还需要放在CPU内
成本代价导致无法做的很大
在这里插入图片描述

在这里插入图片描述

基于哈希(hash)查找的方案

以上2者不够实用
哈希函数是数学计算方法,输入一个页号输出帧号,可用软件,也可硬件加速,采用硬件加速
为加快速度,加一个PID,当前运行程序的标识,PID加页号作为输入,算出对应的帧号
在这里插入图片描述

问题:

  1. 一个输入可能会有多个输出,对于hash而言,一个Input会有多个output,要选出哪个是真的帧号
  2. 做哈希计算,也需要到内存中取数,需要TLB
    在这里插入图片描述
    好处:
  3. 不受制于逻辑地址空间,只跟物理地址空间有关,且较小
  4. 多级页表每个运行的程序都需要一个页表,而这个整个系统只需要1个页表,和多少个程序也没有关系
    代价:
    需要高速的哈希运算机制和有效的解决冲突的机制

总结(20220724)

首先是连续内存分配,逻辑地址空间和物理地址空间都是连续的,分区的动态分配有首先适配方法、最佳适配方法、最差适配方法,解决碎片的方法有压缩式和交换式

其次是非连续内存分配,因为连续内存分配连续内存分配的缺点:
1、分配给一个程序的物理内存是连续的
2、内存利用率较低
3、有外碎片、内碎片的问题
所以出现了非连续内存分配,他的物理内存是非连续的,方法有分段和分页,分段的逻辑段和物理段的大小可以不一样,分页的逻辑页和物理帧的大小要一样

为解决页表过大、需要访问2次内存的问题,有软件解决方法(开销大)和硬件解决方法。
硬件解决方法有:
1、页表大小与逻辑地址有关
基于时间的解决方法——TLB(在MMU中),
基于空间的解决方法——多级列表,
2、使得页表大小与逻辑地址无关,而与物理地址有关的方法
反向列表(解决页表过大)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值