操作系统——内存

内存使用和分段:

内存是如何使用的:

在这里插入图片描述
计算机是通过取指令,执行指令这两步来工作的,当我们需要一条指令,需要通过地址总线向内存读出数据
在这里插入图片描述

当我们将磁盘上的程序发送到内存中,call 40想要执行,就需要将main函数的入口放在内存地址为0的位置,一直向后放,直到main函数,这样call 传向地址总线上的40地址才能正确匹配到地址

但是0地址是唯一的,如果我们想要运行多个程序,他们都使用了40这个地址,显然会发生冲突

在这里插入图片描述
我们可以通过逻辑地址的方式(也就是相对地址),每一个程序对应一个基址,这样程序内的地址就成了相对地址,通过基址+相对地址得到的就是程序在物理内存中的地址,但是这种方式要求我们当我们使用一个地址的使用,需要将这个地址重定位
在这里插入图片描述
重定位有两种方式,编译时重定位和载入时重定位
当我们使用编译时重定位的方式,在我们编译程序的时候就需要将程序的内存物理地址写好在程序中,这样其实和原来的方式没有太大的区别,还是会发生地址冲突
当我们使用载入时重定位的方式,我们在载入程序后,就需要将程序中的地址重新写好,然后这个程序就只能在这个位置运行,不能再移动,这其实也是比较僵硬的方式
在这里插入图片描述
因为程序能可能要交换出内存,这样的方式显然不例如程序的交换,可能交换回来这个地址空间就被人抢了
在这里插入图片描述
其实最好的重定位时机时再程序运行时,进行重定位,这样当程序需要访问一个内存地址,只需要做一个基址+偏移的运算就可以得到
使用pcb来存放base,每一次的换入换出都可能需要更换pcb的值
在这里插入图片描述
在程序中,不同的数据段可能有不同的权限,不同的功能
在这里插入图片描述

我们可以将不同权限的数据分开,这样就成了分段方式,使用不同的段基址+段内偏移号,就可以得到一个段内的数据了
在这里插入图片描述
这样也保证了每个段可以独自的移动
将一个段内偏移和一个段基址就可以得到一个物理地址
pcb中需要存放每一个段的基址

在这里插入图片描述

GDT表就是段表, jmp 0,8 这个8就是段选择子对应某一个进程的某个一个段,GDT这个表是操作系统的段表
LDT表是进程对应的段表
在这里插入图片描述

进程的段基址放在ldt表中

内存分区与分页:

使用一个ldtr寄存器来存放当前运行程序的LDT表
汇编中,如果没有说明段寄存器就默认是cs寄存器
进程切换是ldtr会切换
在这里插入图片描述
当程序需要执行就需要将各个段加入到内存中,这之前就需要我们查找一段空闲内存
在这里插入图片描述固定分区的问题是显然易见的,当一个分区的大小很小的时候,一个大的分区可能导致内存的浪费

在这里插入图片描述
当处于上图情况:

在这里插入图片描述在这里插入图片描述
可变分区的问题主要是,当随着分区不断被分配和释放,可能导致出现分区的间隙,也就是在两个分区之前存在一个很小的内存空间导致分不出去。
在这里插入图片描述
因为这两种方式的缺点在实际系统中不使用这样的内存分割方式,而是使用分页机制
在这里插入图片描述
内存碎片可能导致内存碎片,导致效率低下
在这里插入图片描述

在这里插入图片描述
一个段最多浪费一页
在这里插入图片描述
当我们要jmp 40也就是代码段的40号偏移,已知一个页的大小为100,那么我们可以知道40到第0页中,对应的也就是页框5,得到物理地址540
cr3存放的就是每一个进程的页表地址
在这里插入图片描述
这个是由cpu的mmu来做的
在这里插入图片描述
页框号为3,表示地址为3*4k+240=0x3240

在分页中,弱化了进程空间的概念,当给出一个地址,只需要去该段对应的页表项中找到对应页框得到物理内存地址

多级页表和快表:

在这里插入图片描述当页的大小小了,页表项增加了,这缩小了内存的空间利用率
如果有4gb的物理空间,每页大小为4k,这就导致页表有1M页,这显然大了
在这里插入图片描述段中有一些地址没有使用,比如0-100使用了就记下0号页号,101-200使用了就记下1号页号,集中没有使用的就不记录
在这里插入图片描述
不连续会导致访问内存的次数增加,不利

在这里插入图片描述
在这里插入图片描述
这样当我们建立一个二级页表,我们可以将二级页表中的不需要的内存空间不再建立映射关系,在大表中可能第一个页目录指针对应的是0-40M内存的页表地址,第三个页目录指针对应80-120M内存的地址,但是我们没有对这个空间的访存需求,所以不建立映射,当我们需要访存0-40M物理地址,只需要去找二级页表,得到一级页表的地址,然后使用随机存取的方式取出地址就可以了
在这里插入图片描述
这样有些地址我们不需要映射,比如上图中,我们只需要使用16k内存来管理页表,大表1个,小表3个
这里我们需要进行一个页表目录号的计算
从偏移计算逻辑页表,逻辑页表计算出页目录号
每多增加一级页表就增加了一次访存
在这里插入图片描述
在64位系统中,还是增加了多次访存,引入TLB
在这里插入图片描述

使用电路比对,速度快
在这里插入图片描述
在这里插入图片描述
TLB有效可以用空间局部性原理来证明
在这里插入图片描述

段页结合的实际内存管理模式:

在这里插入图片描述
在这里插入图片描述在程序员眼中,程序拥有4GB空间,当然这是虚拟的,这4gb空间中存在若干段,这些段又被分为若干页,将页存放到物理内存中,再建立这个进程的虚拟内存到物理内存的映射关系,比如在代码段中的地址0x00345008这个地址是在用户代码段中的地址,只需要算出这个地址在虚拟内存中是第几页,然后去查找和物理内存的映射关系,就可以得到这个地址在物理内存中的位置。
逻辑地址相当于带啊吗段地址+偏移地址=虚拟地址(页号+偏移 页号为4gb的页号)
当在只有分段的情况下,段地址+偏移地址得到的就是物理地址
在这里插入图片描述
在这里插入图片描述
将程序看成4gb的工作主要是在编译上完成的,可以将全局地址编译成4gb的大小,然后就可以在将要执行时合理的分配了,比如在windows系统中,每个段的其实地址是有写出的,这个就是段基址,这就可以看成占据了虚拟地址空间,也就是说,要将程序段中的数据映射到物理内存中,也就是从段开始,算出每一个段中每一个页的页号是多少,然后将其映射到物理内存中,对于没有数据的虚拟空间,就可以不用映射了

在这里插入图片描述

示例

在这里插入图片描述
给每个进程分配64M的虚拟地址空间,将每个段的段表设置为一个64M的开始位置
在这里插入图片描述
这意味着,当我们将程序加载到虚拟内存中,需要将全局地址改变到这个进程对应的虚拟空间开始位置开始计算,然后将虚拟内存对应到物理内存中,这样就只需要一张页表,就可以做到虚拟内存到物理内存的映射
在这里插入图片描述
复制页表,然后建立映射
在这里插入图片描述将64M的空间看成一个整体,将父进程中的64M的映射关系拷贝到子进程的64M中,这样复制进程不同的虚拟内存页表都指向了相同的物理内存页框
在这里插入图片描述
在这里插入图片描述
将这一页的权限修改为只读,这样父子进程当需要写的时候,就需要重新分配一个新的内存页用来存储需要写的数据,就可以正常的使用了。

内存换入和请求调页:

在这里插入图片描述在这里插入图片描述我们如何在内存大小只有3g的情况下运行地址空间为4g的程序
在这里插入图片描述将有需要的内存映射到物理内存中,有需要的时候就将虚拟内存地址映射到物理内存上,并换入
在这里插入图片描述
mmu查页表发现缺页,就开始调入页面
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
读磁盘,建立映射
在这里插入图片描述

内存换出:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
我们不可预测程序将来需要使用什么页
在这里插入图片描述在这里插入图片描述
但是,这样的方法在实际情况中也是麻烦的,因为每一次执行指令都需要进
行查表,
在这里插入图片描述
在这里插入图片描述在这里插入图片描述
当需要一页是时候可以直接到mmu进行查询,当在内存中也没有找到这个页,只需要使用硬件来置位的方式就可以实现需要从内存中换出哪个位的选择
在这里插入图片描述在这里插入图片描述
当所有的页面都使用了,clock算法就退化成了FIFO算法,指针即作为清位指针,又作为置换选择指针,这就导致,当一个页面被置为1,当这个指针太久没有经过这个页面,这个页面一直会为1,这样这个页面记录的信息就太久了
在这里插入图片描述在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值