操作系统『3』内存分层体系,地址

一、内存

  • 计算机体系结构:
    在这里插入图片描述
        CPU 负责对软件的控制,内存放置代码和数据,外设(如键盘、鼠标)有各自的功能,发挥其作用。
     

  • 内存层次:
    在这里插入图片描述
        越靠近 CPU 的速度越快,但是存储容量越小。
        作为编程人员,肯定希望希望速度也快,存储空间也大,这就需要借助操作系统来实现。

  • 操作系统在内存管理方面需要完成的目标:
    (1)抽象
        希望应用程序在内存中运行时,不需要考虑底层的细节,比如物理内存、外设在什么地方,只需要访问连续的空间——逻辑地址空间即可。
    (2)保护
        多个应用程序之间可能会相互访问、破坏,所以需要保护机制实现地址隔离。
    (3)共享
        使得进程之间安全、可靠、有效地传递数据。
    (4)虚拟化
        为了让程序获得所需要的内存空间,可以让暂时不需要访问的数据放在硬盘上。

  • 操作系统中采用的内存管理方式
    (1)程序重定位
    (2)分段
    (3)分页
    (4)虚拟内存
    (5)按需分页虚拟内存
        以上过程的实现高度依赖于硬件。由 MMU(内存管理单元):硬件组件负责处理CPU 的内存访问请求。
        

二、地址空间&地址生成&地址安全检查

1.地址空间

     物理地址空间 是和硬件直接对应的; 比如内存条、硬盘等。它的管理和控制是由硬件完成的。
    逻辑地址空间 是程序运行时看到的地址空间, 是一维的、线性的应用程序很容易访问和控制。
    两者的映射关系需要通过操作系统管理。(逻辑地址空间总是要落实到物理地址空间的。)

(1)逻辑地址的生成

在这里插入图片描述

    ① 图,是 C 程序,每个变量名就对应一个地址,这是一种逻辑地址;③图,是汇编程序,已经是更贴近机器语言的,仍然是用符号代表变量和函数,和机器语言相比,能更好地被人阅读。经过链接后,④ 图,是 .o 文件,将变量名和函数名转换成相应的地址,地址是相对从 0 开始的地址空间,是逻辑地址。④ 图到 ⑤ 图的过程,是 应用程序 loader 会把放在硬盘中的执行程序放到内存中运行,这一步会把逻辑地址完成相应的分配,这样应用程序就可以跑起来,相对于执行程序而言,地址会有偏移量,之后所有的程序就可以按照偏移量,进行正确的访问和逻辑的操作。这便是逻辑地址的生成过程,至此,应用程序可以看到的还是逻辑地址。

(2)逻辑地址对应物理地址

在这里插入图片描述

    CPU 要执行一条指令,ALU 会发出请求,携带参数——逻辑地址,然后 MMU 查找该指令的逻辑地址对应的物理地址,(如果 MMU 查找无果,就会到内存中的 map 查找,),查找到的话,CPU 会给组存发送请求,表示需要物理地址的内容——指令的内容;接下来,组存会把内存的内容通过总线传输给 CPU ,这样 CPU 就可以执行指令了。
     ✨操作系统 在其中起到的作用,就是 需要建立好 逻辑地址 到 物理地址 的映射关系。

2.连续内存分配

  • 内存碎片问题
        内存碎片有两种,外部碎片和内部碎片:外部碎片是分配单元之间的未被使用内存;而内部碎片是分配单元内部的未被使用内存 ,取决于分配单元大小是否要取整。
分配策略
(1)最先匹配(First Fit Allocation)策略

在这里插入图片描述
思路:
    分配n个字节,使用第一个可用的空间比n大的空闲块
示例:
    分配400字节,使用第一个 1KB 的空闲块。
    回收的时候可以考虑是否能把空闲块合并,这样就能形成更大的空闲块。
特点:
    简单,找到第一个即返回。但是容易产生外碎片。

(2)最佳匹配(Best Fit Allocation)策略

在这里插入图片描述
思路:
    分配n字节分区时, 查找并使用不小于n (不小于 n 且 最贴近 n 的)的最小空闲分区
示例:
    分配400字节, 使用第3个空闲块(最小)
    可以考虑按照空闲块的 size 进行排序,这样容易在链表中找到最佳匹配的。回收的时候也是要考虑合并的问题。
特点:
    避免拆散大的空间块,外部碎片的产生最小化,比较适合小内存的回收。

(3)最差匹配(Worst Fit Allocation)策略

在这里插入图片描述
思路:
    分配n字节,使用尺寸不小于n的最大空闲分区
示例:
    分配400字节,使用第2个空闲块(最大)
特点:
    一开始就拆大块儿,不适于将来分配较大的空间。


  • 碎片整理的方法
    (1)紧致算法:
        通过移动分配给进程的内存分区,以合并外部碎片。
    需要考虑的是:
        哪时候移动?不应该在程序运行时进行。
        开销?内存拷贝的开销是很大的。
    (2)交换式碎片整理/分区对换(Swapping in/out)
        通过抢占并回收处于等待状态进程的分区,以增大可用内存空间。

3. 非连续内存分配

    以上提到的三个分配策略,都属于连续内存的分配,连续内存分配会导致 内存利用率低,而且存在 外碎片、内碎片的问题。如果采用 非连续分配,除了解决以上问题,还允许共享代码与数据、支持动态加载和动态链接等。

    
    非连续分配,要考虑的问题:如何建立虚拟地址和物理地址之间的转换?从硬件的角度来看,有两种方案:分段 和 分页。

(1)分段

在这里插入图片描述

    逻辑地址空间本身的代码和数据就是由各种 段 组成的,不同的段有各自的属性,分段是为了更好的 分离 和 共享
在这里插入图片描述
    虚拟的逻辑地址空间是连续的,通过分段,可以有效隔离开来,有利于管理、保护和分配。即 一维的逻辑地址 其实就是由不同的段组成的,段可以不连续。

在这里插入图片描述
段访问机制
    段表示访问方式和存储数据等属性相同的一段地址空间,对应一个连续的内存 “块 ”。 若干个段组成进程逻辑地址空间。逻辑地址由二元组(s, addr)表示,其中,s表示段号;addr 表示 段内偏移。
在这里插入图片描述
    如上图所示,如果段号是单独的,和 offset 是分开的,比如 x86 就是典型的这种方式;还有一种,段 和 偏移 合在一起形成一个完整的地址,而没有段寄存器的概念。
    

  • 段访问的硬件实现:
    在这里插入图片描述
         P 是一个可以运行的程序,CPU 要进行寻址,以 单地址 为例,把一个逻辑地址分成两块:段号 和 偏移,通过段号可以找到段所在物理内存的起始地址,通过一个硬件的机制——段表 segement table 保存逻辑地址段号 与 物理地址段号 的映射关系,然后每个段的大小是不一样的,需要了解每个段的起始地址、长度限制等,这些信息 也是放置在段表 中的。然后 CPU 会把 段的长度限制 和 本身的长度 做比对,满足限制的话,说明是合法的寻址;否则,非法,会产生异常,交给操作系统处理(可能会 kill 掉进程)。接下来,就会把起始地址 加上 偏移量,形成物理地址。那么就可以根据物理地址查找到对应的位置,把相应的数据取出来,交给 CPU 进一步处理。
        段表应是操作系统建立的,与硬件有紧密关系。

    
段机制在现有的 CPU 体系中属于使用得较少的,现在绝大部分 CPU 采用的是分页机制。
    
分页和分段的一个区别在于,分页的偏移量是固定的。


(2)分页

    分页也是需要页号 和 偏移,而 和 分段的区别在于,段的尺寸是可变的,而对于分页,页帧的大小是固定不变的。
(frame 是物理页, page 是逻辑页。需要建立起物理页和逻辑页之间的映射。)
① 帧 (物理)
    页帧 是 把物理地址空间划分为大小相同的基本分配单位,是 2的 n 次方,如512 , 4096, 8192。
在这里插入图片描述
在这里插入图片描述
✨ 内存物理地址的表示:二元组 (f, o) ,其中 f 是帧号 (F 位,F 位, 共有2 ^F 个帧);o 是帧内偏移 (S 位, 每帧有 2 ^S 字节)。
    

  • 物理地址 = f * 2 ^ S + o。

地址计算的示例:
    假定16-bit的地址空间,9-bit (512 byte) 大小的页帧,物理地址表示 = (3, 6),求物理地址的位置?
由计算公式:物理地址 = 2 ^ S * f + o,其中 F=7 S=9 f=3 o=6,求得结果为 1542。
    
② 页 (逻辑)
    计算方式与页帧是相似的,区别在于 页号 与 页帧号 的 size 可能不同,(即 通常,页号大小 ≠ 帧号大小)但是偏移量和页帧是一致的,即 页内偏移 = 帧内偏移。
✨进程逻辑地址的表示:二元组 (p, o),其中 p 是 页号(p 位,2 ^ p 个页),o 是页内偏移 (S 位,每页有 2 ^ S 字节)。
    

  • 虚拟地址 = p * 2 ^ S + o。
  • 在这里插入图片描述
    在这里插入图片描述

4.页式存储中的地址映射

在这里插入图片描述
    逻辑地址是连续的,(但物理地址是不连续的)而且每一页的大小是一致的。和分段映射机制类似,程序运行之后,CPU 寻址,这里是指逻辑地址,地址分页 p 和 o,页号作为 index 索引,再需要知道 基值 page base,就可以查找页表 page table,能查到页号对应的 帧号 frame number,帧号加上偏移量 offset ,就可以得到物理地址。逻辑地址空间一般会大于物理地址空间。不是所有的页都有对应的帧。
    

页表

    页表其实是个大数组,每个进程都有一个页表,每个页表对应一个页表项,随进程动态变化而变化页表项标志有:

  • 存在位(resident bit)
  • 修改位(dirty bit)
  • 引用位(clock/reference bit)

    
👉 页表地址转换示例:
    假定:具有16位地址的计算机系统,物理内存大小为32 KB,每页大小:1024字节(即 1k),如果说逻辑页的两个地址为:(4,0) 和 (3,1023),求物理地址。
在这里插入图片描述
    分析页表,第 4 项对应的标志位和帧号,标志位中红色的 “0” 表示 物理页的页帧不存在,即 没有映射关系,会产生内存访问异常,比如查(4,0),页帧不存在; “1” 表示对应的物理页帧确实存在,比如查 (3,1023) 就是存在的,然后二进制的 00100 对应的物理页帧号是 4 然后结合偏移量 1023 ,可以计算出物理地址是 (4,1023)。


👀 页式存储管理机制的性能问题:
(1)内存访问性能问题
    访问一个内存单元需要2次内存访问:“
第一次访问:获取页表项;
第二次访问:访问数据;

(2)页表大小问题
    页表大小问题页表可能非常大,而且很多机器是64位,如果每页1024字节,那么一个页表的大小会是多少?2 ^ 64 ./ 2 ^ 10 = 2 ^ 54 。
    
那么如何解决?
    缓存 (把常用数据存在离 CPU 近的缓存中)、 间接访问。

🖖 解决方法:

快表(Translation Look-aside Buffer, TLB)

    是个缓冲,位于 CPU 内部,缓存近期访问、经常用到的页表项。
在这里插入图片描述

    TLB 使用关联存储(associative memory)实现,具备快速访问性能,CPU 得到一个逻辑地址后,先根据 p 查询 f,如果TLB命中,物理页号可以很快被获取即获取到了物理地址,就只需要访问一次内存;如果 TLB 未命中,就得去查页表了,并且对应的表项被更新到 TLB 中。

多级页表

在这里插入图片描述
通过间接引用将页号分成 k 级,建立页表“树”。”以时间换空间“。

反向页表

    以上页表的大小 和 逻辑地址 的空间大小 有对应关系,希望能建立一种数据结构,使得 存储信息的总容量 与 逻辑地址空间的大小 没有关系,但是又要建立起物理地址 与 逻辑地址的映射关系。
    反向页表的思想就是:通过哈希算法 搜索 一个页 对应的 帧号,

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值