操作系统 内存管理相关知识

cpu执行程序的基本过程

  • 译码器 输入为n管脚,输出为2^n根管脚,编号为从0到2^(n-1),用少的输入端控制更多的输出端
  • 最常用的是三八译码器
  • AD(Address bus)地址总线: 选中一行数据
  • 每一行 8bit 组成8吧B cpu输入端32根线,输出端就可以控制 2^32 ,因此可以控制4G内存
  • DB(Data bus)数据总线: 8根数据线组成数据总线,确定了每一列,通过行和列将1B数据数据通过数据总线传输到cpu内部的寄存器里面,使用R表示寄存器
  • 程序最终是一条一条被读入寄存器内执行的(有限 ,且按照功能进行分类,有通用寄存器和特殊寄存器,特殊寄存器只能被特殊的指令访问,)用户态(访问通用寄存器) <=> 内核态(访问特殊寄存器和通用寄存器)
  • 内存条是一个临时的保存中介
  • 磁盘是一个永久的保存中介
  • 地址总线的选中原理 (译码器原理)
  • 了解四大类存储器的速度和所处的位置  容量大小
  • 寄存器 (cpu内部)> cache(cpu内部) > 内存卡 (cpu外部)> 磁盘(cpu外部)
  • 寄存器只会保存数据;cache也需要将数据拷贝到寄存器里面执行
  • ALU 算数逻辑运算单元 负责运算
  • 举一个例子 计算机计算 3+2 计算器读取3 将3读到R1寄存器,然后读+,ALU会读+,因为+需要两个数,因此通过地址总线形成地址,将2读到R2寄存器,计算,通过R1和R2取数据,然后将数据计算结果存到寄存器R3,然后找地址,将数据结果存储到内存的一个位置,(写回内存)。

CPU位数 OS位数 内存地址总线数 内存数据总线数 逻辑地址位数 物理地址位数

  • cpu位数 和 寄存器的位数相关,如果寄存器的个数是32则cpu是32位;如果寄存器个数是64则cpu是64位。
  • 32位的寄存器可以处理2^32大小的数据;64位的寄存器可以处理2^64大小的数据
  • os位数(操作系统的位数):硬件限制软件;软件可以自定义(软件分成32位或者64位);os位数等价于逻辑地址的位数,二者相等。也等价于虚拟内存的理论大小。
  • 32位cpu只可以安装32位操作系统;64位cpu既可以安装32位也可以安装64位操作系统
  • 数据总线数 如果是8根 如果传输32位数据,需要传输4次;64位 传输数据 需要8次;现实生活中有 8 、16 、32 和 64根数据总线
  • 数据总线:一般考研常规使用的是8根数据总线 ,每次可以传输8位数据,如果寄存器的大小是32,需要传输4次将数据填满一个寄存器;如果是64位寄存器,需要传输8次将数据填满一个寄存器
  • 可访问内存的大小 + 磁盘大小 大于等于 虚拟内存的实际大小
  • 虚拟内存理论大小 大于等于 虚拟内存实际大小
  • 但是现实生活中有 16位 32位 64位数据总线
  • 物理地址总线数 (物理地址总线数):比如上面的例子中,地址总线有32位,每一个地址是由32位0或者1组成,从硬件限制可访问内存的大小。这里属于1,硬件限制,限制了可访问内存的大小。比如电脑是32位的,那么根据可以访问的物理地址总线,有0-2^32-1,也就是4G的内存,即使安装8G的内存条,剩余的空间是无法访问的。
  • 或者2,内存卡限制,比如32位机器安装2G内存卡,剩余的空间无法访问
  • 或者3,软件限制,比如译码器原理,限制输入端输入的位数,限制输出端可以访问的地址
  • 三个限制 ,取最小值作为可访问的内存大小
  • 逻辑地址 是将程序从磁盘拷贝到内存,可以拷贝最大的行数,这个和操作系统的位数有很大的关系

内存管理逻辑图

  • 程序经过编译和链接形成exe程序,从磁盘将程序装入内存执行,进行程序的运行
  • 装入?1,如何装入?2,装在哪里?(1)记录 (表格)  (2) 查询 (表格)

编译和链接

  • 编译,将C语言转化为汇编语言,机器语言
  • 各个模块的逻辑地址,逻辑地址也叫做相对地址
  • 链接 ,将多个有交集的汇编语言、机器语言合并到一起,会改变先前的逻辑地址,经过编译链接之后形成可执行文件
  • LOAD 1,6  将第六行的变量加到寄存器1里面;ADD 1,8 将第8行变量和寄存器1里面的数据相加;STORE 1,10 将计算的结果(寄存器1中的数据)存储到第10行变量C
  • 汇编 每一行指令占据两行,汇编使用逻辑地址指向变量

装入

  • 如果随意装入程序,cpu可能无法找到每一条执行程序。因为编译的代码所使用的的指令是相对本程序而言的,比如 LOAD 1,6;是将第六行的变量放入到寄存器1里面,而cpu会将整个内存条的起始位置作为程序的开始位置,因此,对这个命令使用的位置6和整个内存条的位置6是冲突的,形成地址错位。
  • 地址错位 本质上是由于 逻辑地址和物理地址不匹配 造成的冲突;
  • 物理地址是绝对的;逻辑地址是相对的
  • 将程序从磁盘 拷贝到 内存 ,其逻辑地址会发生变化,指令后面所使用的相对地址也要随之变化,才可以运行。
  • 程序编译使用的是逻辑地址(相对地址);内存卡使用的是物理地址(绝对地址)。
  • OS位数和逻辑地址的位数 是等价的。如果程序编译很长,超出位数的代码无法识别,不可以超过机器程序(2^操作系统的位数)的大小。
  • C语言中 函数名字和变量名字本质上都是地址
  • 解决方案 :1,绝对装入;2,静态重定位装入;3,动态重定位装入

解决虚拟地址和物理地址错位的三种方法

1,绝对装入

  • 装入前就确定好程序的装入位置,使得程序逻辑地址和物理地址对齐,不错位
  • 开发程序的时候就指定我要从  指定的位置上编译程序,比如我的程序执行需要将程序拷贝到内存的第1000行以后,这样内存地址和物理地址一一对齐,不会错位
  • 那么这个程序每次运行永远拷贝到指定的位置

2,静态重定位装入

  • 装入时候,动态指定将程序装入的位置,由装入程序的逻辑地址进行一次性修改,从而避免错位。每拷贝一行就改变一行中的地址,从而避免错位(边装入边修改)
  • 如果不指定,都是默认从0开始作为起始地址
  • 那么每次执行的程序的逻辑地址都是不同的,这个地址是装入前动态设置的,因此是 重定位 的概念
  • 静态是指,这个程序一旦加载到内存,地址就指定了,就不可以改变了;要想移动,只可以关闭程序,重新指定程序的起始位置

3,动态重定位装入

  • 程序运行的时候,利用重定位寄存器来弥补作用,让cpu认为逻辑地址和物理地址是对齐的,不错位
  • 将程序原封不动拷贝到内存,此时逻辑地址和物理地址是存在一个错位。程序拷贝到内存会创建一个pcb,存储相关信息,其中入口地址,指定程序拷贝到内存的位置。
  • 利用CPU内部的重定位寄存器,存储上述提到的内存位置。每次运行的时候,会在指令的后面 异步加上内存的位置,补齐逻辑地址和物理地址之间的错位。
  • 如果程序变化,程序直接移动,直接修改pcb和重定位寄存器里面数值就可以让逻辑地址和程序地址对齐

内存保护

  • 也叫做越界保护
  • 内存保护 由 硬件和os操作系统共同保障
  • 实现方法:
  • 1,上下限寄存器,比如木马程序拷贝到内存中的1000到2000行,那么下限是1000,上限是2000,如果内部程序想访问3500,和上下限对比,不符合,因此报错
  • 2,基址寄存器(重定位) + 限长寄存器(界地址);告诉首地址,通过限长寄存器得到程序的占用空间,因此得到程序的上限

单一连续内存分配

  • 内存卡分为系统区(os操作系统)和用户区(操作软件)
  • 用户区每次只可以装入一个程序
  • 特点:
  • 1,单用户 单任务
  • 2,内存卡利用率极低 因为有内部碎片,程序只用到了一部分
  • 3,通常采用绝对装入的方式

固定分区分配

  • 装入多道程序 
  • 克服单一连续分配只可以装入一个程序的缺点,在用户区进行划分,每个区块分配不同的程序
  • 划分可以都相等 或者 每个区块的大小不一样,减少浪费
  • 特点:
  • 1,用户区分成很多小的分区,每个分区只装入一道程序
  • 2,分区的大小很有讲究,太小装不进程序;太大内存利用率低
  • 3,有内部碎片(内部碎片:内存分给你了,你没有合理使用内存,就叫内部碎片)
  • *外部碎片:内存空间除去分给程序的各个分区之后,剩余的空间不足以放下任何程序,这个剩余的空间不属于任何程序,叫做外部碎片
  • 需要分区说明表 记录分区号 分区的大小 起始位置 状态
  • 提交程序的时候,查看哪一块内存是空闲的
  • 一般使用静态重定位技术

动态程序分配

  • 解决固定固定分区提前设定分区大小的弊端,进程程序要多少给你多少,不多分配不少分配。
  • 如果用户区间只剩下2MB不足以分配程序,那么需要等待先前程序释放资源,比如qq退出,释放了8MB的内存空间,lol立刻占用这8MB中的6MB,剩余2MB,这2MB就是外部碎片
  • 由于程序的进进出出,导致的碎片数量越来越多,空间越来越小。进行碎片合并。将很多碎片合并在一起,形成一个大的区间,这个合并过程是一个随机的事件
  • 需要使用紧凑的技术,较少外部碎片,碎片的 移动  合并,这个移动就涉及到了动态重定位
  • 动态分区 需要分区说明表,每一块分区的大小不确定,动态变化
  • 如果一个程序加入内存,但是有很多区块都可以存放数据,那么这个这个程序如何存放呢??
  • 动态分区算法:
  • 1,首次适应:从内存区间头部开始,第一次可以存放的位置
  • 2,最佳适应:从内存区间头部开始,找一个尽可能不浪费的区块;但这个并不是最佳的,反而会产生更多小的碎片,不可用,只能使用紧凑技术合并更多的碎片
  • 3,最坏适应:从内存区间头部开始,找一个最大的区块;产生的碎片不会很小,反而可以给其他程序使用,因此不一定是最坏适应
  • 4,邻边适应:每次找合适的区块不是从头开始,而是从上一次的位置开始往下找

覆盖技术

  • 软件运行有128kb,要在64kb的内存上运行,覆盖技术要求程序员在设计程序的时候,设计每个程序的启动的先后顺序,将内部分区分为固定区,存储主程序;覆盖区用于代码之间的运行、覆盖。
  • 特色:
  • 1,用在同一个程序进程中
  • 2,覆盖技术实现了小内存运行大程序,但是这不是万能的
  • 3,对程序员要求高 ,考虑性能

交换技术

  • 交换技术发生在内存紧张的情况下
  • 交换技术主要用于不同进程(程序)之间
  • 覆盖技术已经过时,交换技术仍然存在
  • 将处于阻塞状态下的程序拷贝到交换区域,将需要运行的程序拷贝进入内存区,交换是指内存和磁盘之间的交换

分页

基本分页存储

  • 先前使用的固定分区分配产生内部碎片,动态分区分配会产生外部碎片。
  • 每个碎片可能很小,但是积少成多,总和是一个不小的浪费
  • 分散分配:将大的程序进行拆分变成很多的小的碎片,每个碎片分别拷贝到内部或者外部产生的碎片中。
  • 但是以什么作为标准进行切分呢??大小不等,切片很难。因此引入分页思想,都切成一样大小的
  • 特色:
  • 1,程序可以被切块
  • 2,内存也可以被切块
  • 3,切块越小,浪费越小
  • 因为碎片的大小是随机产生的,因此对程序的切片不好处理,思路很简单,实现很难

如何分页

  • 将内存卡(物理地址)和软件程序(逻辑地址)都等分成4kb,然后将软件程序的拷贝到内存卡上面执行,程序的大小和物理内存的分块大小都一致,但是如果不可以整除,会有部分浪费,但是这种浪费很小。
  • 内存、磁盘、程序都会被切块,内存卡的一块叫做 页框(页帧)
  • 程序的片段叫做页面,页面可以被装入页框中
  • 磁盘的分块叫做 磁盘块
  • 磁盘 程序 和 内存 都按照4kb进行切割,这样程序导入 磁盘和内存都很方便;切片的大小需要符合2的指数,2^0 = 1; 2^2 = 4;  2^4 = 16;
  • 为什么分块使用4kb??这个不确定,有1Kb、16kb和32kb,4kb最常用,都是2的n次方的整数倍
  • 设置mmu,就可以实现对内存、程序和磁盘的kb大小的选择,切换1kb、4kb和16kb

页表

  • 内存卡的分块编号,从0开始排序,其编号也叫做物理块号、页框号、页帧号
  • 程序 切分,也会进行编号,从0开始,其编号叫做页号、页面号
  • 将内存卡切分的编号和程序切分的编号对应起来,叫做页表。这个页表存储在内存中,每个进程都有自己的页表。创建进程的同时会创建pcb,pcb会存储这个页表的信息,从而让操作系统找到这个页表
  • 页表有俩列,好多行,第一列存储页号,存储逻辑地址;第二列存储物理块号,也是物理地址
  • 页表项 是 页表的一行
  • 页表 通过pcb被查询到
  • 页表只能记录块和块之间的映射关系,4kb 可以存储很多的代码,因此不会得到每一行代码在哪一块中的哪一行等相关信息

页表、物理地址、逻辑地址三者之间的关系

  • 数学关系
  • 二进制向左移1位表示十进制除以2
  • 人类视角  十进制 整除取整为页号;求余为业内偏移
  • 机器视角  二进制 高位为页号;低位为业内偏移
  • 32位 以4k作为一个页,4k = 2^12 因此,低12位作为页内偏移,12到32位作为页号;读高20位得到哪一页(页号),读低12位知道属于哪一行(业内偏移)

  •  通过逻辑地址 -> 页表(页号) -> 通过页表里面的逻辑地址和物理地址的对应关系,找到物理块号,将物理块号 和 业内偏移合并在一起就得到了物理地址
  • 逻辑地址和物理地址里面的业内偏移 是一一对应的,因为把程序切片拷贝到内存,代码里面的地址是相对的,起始到终止的差距就是业内偏移。物理块号代表这个物理块开始的地址,加上这个代码的业内偏移,也就是物理块结束的地址。
  • 编号为何从0开始?整除取整直接得到页号

基本分页 基本地址变换机构

  • 对逻辑地址进行上面的操作,就可以得到页号,通过页号查询页表,查询到某一页程序被装载到内存中哪一个物理块里面,查询到物理块之后和业内偏移量拼接在一起,构成一个物理地址
  • 上面这些需要使用到地址变换机构,才可以得到业内偏移等信息
  • 逻辑地址 前20位表示页号,后12位表示业内偏移量。 通过页号 和 匹配的物理块号对应,
  • 页表存储在内存里边,页表记录的是页号和物理块号(页框号)的对应信息
  • 页表寄存器,存储在cpu里面,前半段存储页表的起始地址,后半段存储存储页表长度(程序放到内存里边执行的时候最大的长度)。这个是唯一的,一级页表,后面会有多级页表,动态通过pcb进行更新
  • 页表寄存器 相当于给定指针 + 数据长度,得到的这一块内存就是存储的页表信息
  • 页表长度 存储的是所有页号的信息
  • 页表长度 *  4KB = 程序的大小
  • 页号 大于 页表长度,说明这个程序不属于当前程序,产生 越界中断。如果小于 则属于合法的,就可以进行查表,CPU先根据页表寄存器里边存储的页表起始地址找到 页表开始的地方,根据页表存储的页号,在页表里面查询。通过页号找到后面存储的页框号(物理块号),将页框号(物理块号) 和 业内偏移量拼接在一起,就形成了物理地址
  • pcb更新页表寄存器的数值

考点

  • 执行一条指令一共会访问几次内存?
  • 执行指令,需要物理地址,1,寻找物理地址,2,读入cpu内部,3,执行指令
  • 1,寻找物理地址:利用页号到内存里边的页表查询物理块号,拼接形成物理地址,一次访问内存
  • 2,读入cpu内部,找到物理地址需要将指令拷贝到CPU的内部,一次访问内存   然后执行命令,一级页表的前提下,需要访问两次内存
  • 如果是两条指令 则是4次

具有快表的地址变换机构

  • 快表也是页号和物理块号的拼接,相对存储在内存中的页表,快表存储在页表寄存器,是比页表先一步被访问。主要的目的是记录先前曾经访问过的历史记录,类似于电脑的快捷访问,为了减少访问内存的次数,但是存储的条数很少。因为存储在寄存器,因此CPU先调用寄存器很快,如果找不到才会访问内存。
  • 因为快表会保存最新的访问记录,是一个动态更新的过程,因此在访问内部指令的时候有可能会查到有可能查不到,有一定的概率。这个叫做命中率,局部性原理 时间 + 空间
  • 问题:执行1条指令,命中率是90%,那么需要访问几次内存?如果快表存在 1次;如果快表不存在需要两次;乘上对应的概率 总的访问内存次数 = 0.9 * 1 + 2 * 0.1 = 1.1
  • 因此:执行10条指令,命中率是90%,那么需要访问几次内存? 10 * 1.1 = 11次,相较于没有快表,2 * 10 = 20次
  • 快表 命中率很高 是因为程序的局部性原理,也就是for等循环,在这个地方执行很多次,局部原理 体现在时间和空间局部性

两级页表

  • 引入两级页表的原因 
  • 一级页表 页号 + 物理块号 组成的页表项,一共有n个页表项
  • 一个页表项有多大?估计
  • 估计的逻辑:1,逻辑地址 (程序最大空间) -> 2,页面大小 (视情况而定,4kb、16kb) 3,做多分几页;4,页号位数;5,估计页表大小项 补充
  • 页表项确定之后,一个页表项有多大 ,因为一个页表很大,如果多个页表进入内存,会很卡,考虑到分页的时候,程序和内存都可以被分块,页表是不是也可以分块??
  • 发明一个页表,记录页表的切块,变成了两级页表的概念

如何设计两级页表

  • 条件:32位操作系统 4kb页面大小 4B页表项大小
  • 设计
  • 1,按照最大程序进行切割
  • 2,页表切块,块大小 = 页面大小
  • 3,当一个页表可以装在一个页面之内时,多级页表就设计结束
  • 4,逻辑地址切块,块位数 = 该级页表每块容纳的页表项

如何设计多级页表

  • 条件:64位操作系统 4kb页面大小 4B页表项大小
  • 设计
  • 1,按照最大程序进行切割
  • 2,页表切块,块大小 = 页面大小
  • 3,当一个页表可以装在一个页面之内时,多级页表就设计结束
  • 4,逻辑地址切块,块位数 = 该级页表每块容纳的页表项

虚拟内存

引入请求分页的原因

  • 将QQ程序拷贝到磁盘,由于文件管理,将qq程序在磁盘上进行存储。运行的时候,将QQ程序从磁盘拷贝到内存,QQ程序的登录界面只会执行一次,体现了一次性,如果他只执行一次却一直留在内存会导致内存的浪费,驻留性。因此 需要优化一次性和驻留性,
  • 优化的依据,程序的局部性原理,程序中有太多的循环,太多的模块
  • 如何优化,按照需要分批装入、调出  ->  请求分页存储管理  (虚拟内存)
  • 请求分页管理的操作流程  ->  运行程序之前,为程序分配小于整体大小的内存空间,比如先装入登录模块的程序,登录完成之后,将登录模块的程序调出,将需要的程序按照需要逐个装入。

请求分页的工作原理

  • 在内存的一个地方存储一个QQ程序的页表,查询页表实现逻辑地址和物理地址的转换,从而得到程序的片段存储到物理磁盘的哪一个块里面,以及存储在物理块里面的哪一行
  • 在cpu的内部存储一个快表,快表是程序的页表历史记录的备份。因为基本分页,页表是存储的QQ程序切割之后存储到内存中物理块的对应的逻辑信息
  • 请求分页的工作原理:1,大致的流程一致,但是页表记录的信息不一样。因为按照需求,需要将文件切片动态的植入换出,这就需要记录哪些页面已经在内存中,页面执行的次数等信息,因此引出了(置换算法),动态将需要的页面放入内存中,替代先前的使用过的,不需要的页面
  • 基本分页页表 记录了每一块的逻辑地址和物理地址的对应关系;但是 对请求分页页表而言,有的时候找不到,这个块还没有装载到内存中,需要将这个块替换到内存中分配的驻留集里面来使用。
  • 相较于基本分页,请求分页对逻辑地址和物理地址的对应关系虽然也需要通过页表,但是并不简简单单,期间多了mmu,虚拟地址到物理地址翻译

助留集 和 工作集是一个意思

  • 二者是一个概念,就是操作系统给单个进程分配的几个物理框所装的页面的集合
  • 每次程序运行的时候需要将程序从磁盘拷贝到内存,根据生存时间的不同分为主程序页面 (常驻内存的页面)  和  子程序页面
  • 比如 主程序界面作为一个界面UI,这个常驻内存,除非程序退出或者异常退出;而不同的功能就是子程序,需要的时候调入内存执行,使用完之后调出内存
  • 驻留集的大小:不能过大,如果过大,退化为基本页表,浪费内存;如果过小,置换页面发生频繁,运行程序的时候会很卡;要适中,相对的概念

三种策略  分配助留集的大小的策略

  • 固定分配局部置换:计划经济策略,非常死板,计划赶不上变化,程序是变化的;局部是指按照需求,所需的只可以替换自己事先分配好的页面
  • 可变分配全局替换:低级的市场经济策略,盲目扩大生产,产业泡沫;如果程序需要更大的内存空间,会进一步动态增加驻留集的大小,但是会导致装入程序的数量下降,先前分配给程序的驻留集不会减少;
  • 可变分配局部替换:高级的市场经济策略,抽肥补瘦,动态调整,十分灵活;减少缺页率。每个程序所需要的驻留集的大小是动态调整的
  • 缺页率 :当分配的物理块(驻留集)一定的时候,调入和调出的频率是成正比
  • 可变分配局部替换在n1 n2之间动态变化,协调缺页率和物理块数量之间的关系

页表改进 和 缺页中断

  • 基本分页是将程序所有的内容拷贝到内存中;请求分页是按照需要将需要的装入内存,动态装载调出
  • 请求分页页表 具体列(字段)如下
  • 页号 0 - n
  • 物理块号 
  • 状态位 有效位,标志是否在内存中,否则缺页中断,并且进入阻塞状态;如果物理块有数据,但是状态为0,表示并没有被装入,状态位控制物理块是否有效;有效的位数要小于驻留集的大小;如果产生缺页中断,利用调度算法从磁盘将需要的页拷贝到内存
  • 外存地址 磁盘块号,如果需要的页不在内存,需要从磁盘块导入页
  • 为置换算法提供参考使用的参数 访问字段(统计使用,区分程序是长期使用还是短期使用,执行次数越少的越容易被调出)、修改位(对于变量的数值修改需要从内存改回磁盘)、使用位(clock算法使用)等
  • 如果需要的页不在内存中 就会产生缺页中断,然后从磁盘里面取页面到内存中,替换

页面调度时机

  • 程序开始运行的时候,使用预调页策略(局部性原理),程序员指定的,main函数,操作系统底层将其作为程序的入口
  • 程序的运行过程中 修改请求页表相关信息
  • 程序运行中,发生缺页时,比如程序启用不同的功能;调入一页页面,请求调页策略,(页面置换算法),使用硬件中断,中断处理程序,启用页面置换算法,将新的页面替换旧的页面

置换算法

OPT页面置换算法 最佳  向未来看

  • 算法思想:淘汰以后永不访问 或者 将来最长时间不再访问的页面
  • 算法特点:不可以预测未来,因此这个算法不能实现
  • 推断出   缺页中断次数 / 页面置换次数   
  • 缺页次数 -  页面置换  =  工作集(驻留集)
  • 理想化,很难实现,因此其余算法是不可能超过他的
  • 发生缺页中断的时候 除了刚开始没有数据,剩余的都会发生页面置换
  • 下面的例子 发生了9次缺页中断

FIFO页面置换算法

  • 算法思想:淘汰先调入的页面,队列实现 
  • 算法特点:简单、性能差、且有belady异常
  • 推断出 缺页中断次数/页面置换次数
  • 15次中断 15-3 = 12次 页面置换

LRU算法 最近未使用算法  向历史看

  • 算法思想:淘汰最近未使用的页面 (使用过去来预测未来)
  • 算法特点:性能优异,接近最佳置换算法,需要硬件栈的支持,开销极大
  • 推断出 缺页中断次数 / 页面置换次数

CLOCK算法 又叫NRU(Not recently used)

  • 算法思想:通过钟表扫描法,淘汰最近未使用的页面(页表增加一个使用位)首次装入置1;再次访问置1;扫描时将1变为0
  • 算法特点:由于最近未使用和最久未使用的思想接近,因此CLOCK 算法和LRU算法性能很接近
  • 推断出 缺页中断次数 / 页面置换次数
  • 但是CLOCK算法性能更高,不需要硬件,而LRU算法需要硬件栈的支持

改进CLOCK算法

  • 算法思想:通过钟表扫描法,淘汰最近未使用的页面中未修改页面
  • (u,m) use modify
  • (0,0) 未使用未修改
  • (0,1) 未使用已修改
  • (1,0) 已使用未修改
  • (1,1) 已使用已修改
  • 算法特点:相比CLOCK算法,减少了页面回写磁盘的概率,从而省却了回写的时间 (I/O时间)
  • 对变量的数值修改会导致内存和磁盘数据的不一致,因此要根据修改的内容更改磁盘数据;先淘汰未使用的,就减少更新数据所带来的IO操作
  • 算法步骤:1,按照钟表扫描法,寻找(0,0)用于替换,找不到就进行第二步;2,重新执行钟表扫描算法,寻找(0,1)用于替换,在扫描中,将(1,0)改为(0,0),(1,1)改为(0,1),找不到回到第1步
  • 注意事项:第1步只查不修改;第二步边查边修改
  • 改进CLOCK算法更加细腻

从何处调入页面,调出的页面存放在哪里?

  • 临时存放程序的副本 -> 磁盘必须要有一块对换区(swap)
  • 可修改程序 ->  变量 (已修改 / 未修改);可修改程序如果已经修改,回写磁盘,写到对换区里面的程序副本里面
  • 不可修改程序 常量
  • 如果对换区很大的时候,每次运行的时候,将程序拷贝到对换区,程序运行的时候,是将对换区里面的程序拷贝到内存
  • 对换区大小问题(运行程序,将程序从文件夹拷贝一份到磁盘的对换区,然后从兑换区拷贝程序到内存区)
  • 对换区足够大,从磁盘的对换区将数据文件拷贝到内存
  • 对换区不够大,对换区只装入可修改程序,不装入不修改程序,不可修改程序从程序安装文件夹读取
  • unix 方式:读取文件都是从程序安装文件里面,但是回调的时候,无论是可修改程序还是不可修改程序都写到对换区里面;然后第二次以后就会从对换区进行数据交互
  • 1,从何处调入页面?从磁盘的对换区将数据文件拷贝到内存
  • 2,调出的页面存放在哪里?将修改的内容回写到对换区,不可修改程序不会回写到文件夹
  • 不对源文件进行操作,防止不同用户之间的数据干扰
  • 程序安装目录是原件,对换区拷贝的是程序的副本

虚拟内存的大小

  • 虚拟内存 小于等于 逻辑地址支持的最大空间(软件限制) 软件支持的容量很大,不需要考虑,一般硬件限制就是虚拟内存可以支持的最大内存
  • 磁盘装载大程序的一部分 + 内存装载大程序的一部分,合起来使大程序在小内存内运行,通过对换区,实现数据的交互
  • 64位OS -> 2^32 * 4GB
  • 32位OS -> 4GB
  • 虚拟内存 小于等于 (内存卡 + 磁盘)硬件限制
  • 用小内存运行大程序
  • 考题形式:在一台实现了虚拟内存技术的计算机里面,最大支持运行多大的软件
  • 游戏由程序、数据、模型(人物)、过渡动画等组成

抖动现象

  • 发生时间:如果驻留集不够大的话,置换页面时就可能会产生抖动现象(对换区 和 内存区 之间交换数据),又叫颠簸
  • 特点:1,频率高;2,来来回回

虚拟地址和物理地址之间的翻译

CPU执行一条指令的过程

  • 通过地址翻译,由虚拟地址得到物理地址(先查快表,再查页表)
  • 通过物理地址,将指令读到CPU内的寄存器(ALU)里面执行
  • 页表 :页号、物理块号、有效位 三个最关键
  • 快表查询:直接映射(Hash查找)、全相联映射、组相联映射
  • 全相联映射:快表和页表一样,查询的时候需要从头查到尾
  • 因为 全相联映射 内部存储的条目是无序的,查询比较浪费时间,因此改进为组相联映射
  • 2路组相联映射,是指将先前的两个条目组合在一起,形成一组,相较于先前的全相联映射多了组索引、TLB索引,他俩是通过 页号 进行分解得到的。
  • 虚拟地址(逻辑地址结构):将先前全相联映射中的页号p化为TLB标记和组索引、业内偏移w不变;
  • 如果是8条目2路组相联,分成四组,将页号的后两位(00,01,10,11表示组号)作为组索引,剩余的作为TLB,在组索引唯一的条件下,TLB是唯一的标识
  • 只有地位作为组索引,高位仍然满足递增序列,且唯一

虚拟内存-虚拟地址到物理地址的翻译 例题

系统满足如下条件,

  • 有一个TLB与一个datacahe
  • 存储器以字节为单位进行编址 ;以字节为单位进行编址,一行8bit作为一个地址,一行作为0;两个字节为单位进行编址,将先前的两行编为0;全字,四个字节编址
  • 虚拟地址14位
  • 物理地址12位
  • 页面大小64B
  • TLB四路组相联,共16个条目
  • data cache是物理地址,直接映射,行大小为4字节,总共16组
  • 请翻译虚拟地址
  • 0x03d4 ;
  • 0x00f1 ;
  • 0x0229;
  • 有快表,先到快表里面查询,将虚拟地址按照快表的格式进行切分

 

基本分段管理

  • 基本分页是将程序所有文件以4kb作为一个切块,存储在磁盘的一段空间;基本分段是按照功能或者模块将相关联的代码作为一个整体,分散存储在磁盘中
  • 分段的好处:程序多开时可以共享数据;分段可以实现程序多开,或者多个程序公用一个程序段
  • 比如qq程序开了两个,登录不同的qq号,但是有些功能是共享的,比如网络,因此将网络的代码进行复用

如何进行程序分段

  • 按照程序(进程)自然段进行划分,这个流程是由编译器决定的
  • 段长:每段段长都可能不一样,和程序本身的结构相关
  • 分页有页表,记录程序转入到内存的位置,那么分段也应该有段表,功能一致,记录
  • 页表:记录程序的哪一页被记录到内存中的哪一块
  • 段表:记录程序的哪一段被记录到内存中的哪一块

段表

  • 基本分段的段表,每个进程都有自己的段表
  • 段号、段长、内存起始地址(因为段长不一样,不可以向页表一样,使用物理块号(等分),因为每一块大小都是4kb,因此可以通过 物理块号 * 4kb 计算得到物理地址)
  • 通过段表 共享数据
  • 分页存储管理通过查询快表和页表,将逻辑地址翻译为物理地址,从而cpu可以到具体的位置执行指令

物理地址、逻辑地址和段表之间的关系

  • 段号、段内偏移
  • 段内偏移w:由于每一个程序段的大小不一样,以最大的作为段内偏移
  • 到段表查询,得到物理的起始地址b,则物理地址等于b + w

  • 低16位表示段内偏移 请翻译逻辑地址 0x000301F4

分段地址变换机构

  • 计算机步骤
  • 1,根据逻辑地址的前几位得到段号,如果段号大于段表存储的最大长度(段表长度),则产生越界中断,否则合法
  • 2,如果合法 通过起始位置 + 段号 * 段表项长度 =  段表项地址   得到段表项地址b
  • 3,通过 E=b+w  段表项地址 + 段内偏移 = 物理地址
  • cpu执行一条指令 需要访问几次内存?两次  1,地址翻译,需要查询段表,得到物理地址;2,通过物理地址到内存读取cpu指令到cpu内部执行

分页和分段的地址空间维度

  • 分页的地址空间是一维的,因为只要给定页面大小这一个参数就可以划分逻辑地址的结构,比如每个大小都是4kb,(4kb = 2^12B)因此业内偏移是12位,页号占了20位
  • 分段的地址空间是二维的,不可以通过段长计算段号和段内偏移的位数,因为每段的长度都不一样,因此需要给出这两个参数

基本段页式管理(综合段式 和 页式)

引入段页式原因

  • 页式存储管理:通过程序与内存的切成小块,分散和分配内存,减少内存碎片,提高内存利用率。机器的角度
  • 段式存储管理:通过将程序先按照自然段(模块)进行分段,达到通用段可以共享的目的。从人类的角度出发
  • 段页式存储管理:先将程序按照自然段进行分段,再将每个自然段切成等大的页。从而汇聚两者的优势

如何分段和如何分页

  • 先分段 再分页
  • 分段,由编译器完成,将自然段进行分段
  • 分页,将分号的段按照4kb进行切分,每4kb作为一个页,不足4kb的碎片,会出现不足一页的情况 ,这样的内部碎片很小且很少
  • 因为分成段的数量就很少,而且仅仅在最后的时候会产生碎片,因此碎片很小且很少

段表和页表

  • 段表和页表配合使用之后,先前的段表记录段号、段长和段起始地址变成了,段号、段长(页表长度)和页表起始地址
  • 因为对每个段进行分页,因此每个段都有自己的页表起始地址
  • 只有一个段表,段表中的每个段表项都有自己对应的页表
  • 还实现不了逻辑地址和物理地址的转换,需要更进一步操作

物理地址、逻辑地址、段表、页表之间的关系

  • 页号p 业内偏移w : 分页的逻辑结构  -> 查询页表  得到物理地址 物理块号b b|w
  • 段号s 段内偏移w : 分段的逻辑结构  -> 查询段表  得到物理地址 物理块号b b+w
  • 段号s 页号p 业内偏移w : 段页式逻辑结构 ->  先查段表再查页表(因为先分段再分页)

段页式地址变换机构

  • 将逻辑地址变换成物理地址
  • 1,取出段号S和段号表存储的段号比较,如果大于等于最大段表长度,则报越界中断错误;如果小于等于段表长度,查询页表;通过起始地址 + 段号 *  段表项长度 计算得到页表
  • 页表的计算方式一样,得到物理块号
  • 物理块号b 和 段内偏移w 得到物理地址 b|w
  • cpu执行一条指令需要执行几次内存?一共需要三次
  • 1,地址翻译,需要查询段表,查询页表,得到物理地址;两次
  • 2,通过物理地址到内存读取cpu指令到cpu内部执行   一次

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/446649.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Chrome浏览器必装插件!尤其程序猿!

Chrome 浏览器有一个好处&#xff0c;就是插件极其丰富&#xff0c;只有你想不到的&#xff0c;没有你找不到的&#xff0c;这恐怕是 Chrome 浏览器被众多爱好者钟爱的原因吧。 言归正传&#xff0c;今天来给大家推荐 10 款我自己珍藏的 Chrome 浏览器插件。 1、crxMouse Ch…

英语口语-文章朗读Week10 Monday

英语文章 Here are some valuable suggestions which may assist you in landing good job First, make your resume clear and associate it with the position you are applying for. Try to add details like your temporary jobs at college or your former jobs Second, …

英语口语-文章朗读Week10 Wednesday

英语文章 Everyone needs sleep for survival, but how much? It is said that eight hours of sleep is fundamental to a healthy person. But today, many people are sacrificing their sleep time。 Modern people have so many alternatives: cell phones, PCs, TVs, g…

嵌入式Linux多任务编程 进程 管道 命名管道

进程 进程是一个可并发执行的具有独立功能的程序关于某个数据集合的一次执行过程&#xff0c;也是操作系统执行资源分配和保护的基本单位。程序的一次执行就是一个进程一个程序可以派生多个进程多个不同程序运行的时候&#xff0c;也会有多个相对应的进程与其相互对应进程是动…

英语口语-文章朗读Week10 Thursday

英语文章 There are many customs and traditions in Chinese civilization. Here, we will talk about the development of the way people greet each other: In ancient times, people had to kneel to those who were superior to them. This custom remained until the …

Linux进程之间通信 信号

2) SIGINT 程序终止(interrupt)信号, 在用户键入INTR字符(通常是Ctrl-C)时发出&#xff0c;用于通知前台进程组终止进程。 3) SIGQUIT 和SIGINT类似, 但由QUIT字符(通常是Ctrl-\)来控制. 进程在因收到SIGQUIT退出时会产生core文件, 在这个意义上类似于一个程序错误信号。 15)…

Linux进程之间通信 消息队列

使用命令 ipcs -q 查看对应的消息队列代码 文件接收者 #include <sys/types.h> #include <stdio.h> #include <unistd.h> #include <string> #include <signal.h> #include <wait.h> #include <sys/msg.h> #include <cstring&g…

c++面向对象高级编程 学习二 带指针的类

带指针的类&#xff0c;必须要自己写拷贝构造和赋值构造 拷贝构造&#xff1a;参数和类的类型一样的构造函数 赋值构造&#xff1a;重写操作符&#xff0c;且其参数和类的类型一样 class String { public: String(const char* cstr 0); String(const String& str); Strin…

英语口语 week11 Tuesday

英语文章 It was a cold and gloomy winter afternoon, people with their chilled hands tucked into their pockets or hidden in their sleeves. Fred was in a depressed mood, just like the weather,for he failed to get any award in the debate competition When he …

进程之间通信 共享内存

命令 ipcs 命令查看共享内存、消息队列、管道等相关信息ipcs -m 查看共享内存的信息代码 创建共享内存共享内存 关联 进程分离共享内存删除共享内存 #include <sys/shm.h> #include <iostream>#define BUF_SIZE 1024int main() {int share_id 0;//创建共享内存i…

c++面向对象高级编程 学习三 堆、栈和内存泄漏

栈&#xff0c;是存在于某作用域的一块内存空间。在函数体内声明的任何变量&#xff0c;其所使用的内存空间均来自于栈。 堆&#xff0c;是指由操作系统提供的一块global内存空间&#xff0c;程序可动态分配获得若干内存空间块。 new操作符生成的对象所占用的内存空间即是从堆中…

clion编写C++ 使用多线程时候,CMakeLists.txt书写,引用-pthread

添加如下一行 set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread") 具体的例子 cmake_minimum_required(VERSION 3.17) project(mutex_learn)set(CMAKE_CXX_STANDARD 14)set(BOOST_ROOT "/usr/local/include/boost") #添加头文件搜索路径 include_direc…

c++面向对象高级编程 学习四 静态、类模板、函数模板

静态static&#xff1a;静态数据和静态函数&#xff0c;在内存中只有一份&#xff0c;不会随着创建对象的数目的增加而增加 static数据&#xff1a;比如银行的account类中&#xff0c;账户名是普通数据&#xff0c;100个对象会有100个账户名&#xff0c;但利率都是相同的&#…

线程的编程

完整代码 #include <sys/shm.h> #include <iostream> #include <unistd.h> #include <pthread.h>void * child1(void *arg){pthread_t tid pthread_self();printf("1 thread %lu \n",tid);}int main(int argc,char* argv[]) {int result{…

英语口语 week11 Friday

英语文章 I very much like simplicity in life. For me, college is far more than a place to improve my intellectual abilities Every weekend, I usually have a walk along the way to the front gate of Mount Qingcheng, enjoying the intense aromas of flowers on …

c++面向对象高级编程 学习五 组合、委托与继承

组合 composition 表示has a queue类中有一个deque容器&#xff0c;这种关系叫做 组合 queue中的六个函数都是调用c的函数完成的 template <class T> class queue { ... protected: deque<T> c; // 底層容器 public: // 以下完全利用 c 的操作函數完成 bool empt…

英语口语 week12 WednesDay

英语文章 Chengdu, a city with a long history, has always enjoyed the reputation as " The Land of Abundance" . It has been noted as one of the most livable cities in China, partly resulting from its favorable natural conditions and wealthy produc…

c++面向对象高级编程 学习六 虚函数

虚函数&#xff1a;在成员函数前面加上virtual&#xff0c;函数就变成了虚函数 继承函数&#xff1a;子类可以调用父类的函数&#xff0c;叫做继承了函数&#xff0c;即函数的调用权 三种函数&#xff1a; non-virtual 函数&#xff1a; 你不希望 derived class 重新定义 (ov…

C++ 数据结构 线性链表

#pragma once 减少头文件组合&#xff0c;降低编译出错的概率作用等效于 #ifndef FUNC_H #define FUNC_H代码主体#endif 线性表的定义 排队问题 简单的线性表 (物理 或者逻辑结构)1&#xff0c;数组2&#xff0c;链表线性表相关操作&#xff1a;1&#xff0c;线性表初始化2&a…