引言
上一篇笔记讲述了内存的地址空间抽象,但是还留下了问题,那就是当软件很大的时候虽然利用Swapping技术可以运行,但是每次交换整个进程的空间开销不容忽视,虽然近年来内存也有增长,但是软件大小增长的速度远大于内存增长的速度。
一个解决方法是Overlays(覆盖),Overlays将程序分割为多个片段,称为覆盖,当程序开始时,覆盖管理器加载覆盖0,执行完成后,通知覆盖管理器加载覆盖1,然后覆盖1会在覆盖0top上(如果有空间),或者直接在覆盖0(如果没空间)。虽然,换入换出覆盖块由操作系统完成,但是需要程序员将程序分块,这是一个复杂的工作,并且非常容易出错。因此这种技术无法普及,因此人们又提出了新的解决方案,这次是完全交给系统完成,那就是今天要学习的一个技术-虚拟内存。
基本概念
原理
每个程序都有自己独立的空间,并且这个空间分了多个固定大小的块,这些块通常叫做页,每一个页都有一个连续的地址范围,每一个页都映射一个物理范围叫页框(页框的大小通常和页是一样),程序运行不需要所有的页都在内存中,当程序引用到在物理内存中的地址空间时,由硬件(MMU)完成映射;如果不在内存中,由操作系统载入内存并重新执行失败的指令。
页框
物理内存中对应虚拟内存的页叫页框,大小和虚拟内存页大小一致。(RAM和磁盘交换数据是以页为单位的。有不同页面大小混合使用的)
虚拟地址
-
虚拟地址是程序在虚拟空间生成的地址,类似于上一篇讲的逻辑地址,它不是真实的物理地址,需要通过一定的转换才能得到物理地址。
-
简单虚拟地址结构,分为两部分,前n位表示页编号,后m位表示偏移量
-
一个例子:假设一个系统页大小为4Kb,而应用程序需要的空间为64Kb,虚拟页有16个,因此页编号需要4位,而偏移量需要12位,总共16位就可以表示虚拟地址
页表
-
页表是一个列表项的集合,最简单的虚拟地址分为两部分,前n位表示的页编号便是页表的索引(这里的页表是很简单的页表,后边在讲如何解决大虚拟内存时会讲到多级页表)
-
页表项示意图
-
Present/absent位,表示虚拟页是否在内存中
-
保护位,简单用一个位0-r/w,1-只读。或者用3个位,分别表示可读、可写和可执行
-
修改位,当一个页面被写入时该位会自动修改,表示该页是脏的
-
引用位,当一个页面被访问时,该位会被设置,它的值可以用来帮助OS在缺页时选择被淘汰的页面
-
禁止缓存位,设置该位代表该位禁止被缓存,用于I/O设备,如果I/O设备有独立的内存空间,该位不需要使用
-
-
不同计算机的页表项大小可能不同
内存管理单元(MMU)
-
作用: 解析虚拟地址映射的物理地址,数学形式: F ( V A ) = P A F(VA) = PA F(VA)=PA
-
MMU工作示意图
-
虚拟内存映射物理内存示意图
上图是程序的虚拟空间64K,内存是32K,页和页框为4K,可以看到0-4095映射到8192-12287
-
MMU映射过程
- MMU内部处理流程
- 虚拟地址8196取出高4位计算页表索引,0010表示2,因为找到索引为2的页表项
- 通过Present/absent位判断虚拟页是否在内存中,此处的值为1,说明在内存中,找到页框号110;否则MMU发现虚拟地址找不到映射的物理地址,使CPU陷入操作系统(缺页中断),OS会选择一个很少使用的页框交换出去,重新执行陷入OS的指令
- 将页框号+上偏移量就是物理内存地址,放到bus上
分页问题
加速分页-TLB
-
分页系统面临的两个问题
- 虚拟内存地址映射为物理内存地址必须快
- 如果虚拟地址空间很大,那么页表空间也要很大
-
解决方案-TLB(转换检测缓冲区)
- 原理:通过观察,大部分的程序多数情况都是反复访问很少的的页,也就是说,只有很少的页被反复访问,大多数页很少访问,TLB硬件一般在MMU里。TLB示意图
- 原理:通过观察,大部分的程序多数情况都是反复访问很少的的页,也就是说,只有很少的页被反复访问,大多数页很少访问,TLB硬件一般在MMU里。TLB示意图
-
MMU硬件TLB管理
当TLB失效时,有MMU硬件负责查找并且装载,主要的好处是一个简单的MMU可以节省芯片的很多空间让给缓存和其他可以提升性能的组件,TLB工作原理图
-
软件TLB管理
当TLB失效时,会生成一个TLB失效并将问题交给OS解决,查找和装载TLB由OS完成
- 减少TLBmiss:OS会预加载,系统推断接下来需要使用的页
- 降低TLB miss时的开销
- 存在问题:如果用软件管理TLB,当TLB实现时,会通过搜索页表索引页,假如此时存放页表的页不在TLB中,就会引起二次TLB失效
- 解决办法:在内存上固定区域维护一个大(比如4KB)的TLB表项的缓存,该固定区域的页一直在存在TLB中,当TLB实现时,先查找TLB的缓存
- TLB miss类型
- soft miss(软失效):TLB未命中,但是页在内存中
- hard miss(硬失效):TLB未命中,且页不在内存中,开销将非常高
- minor page fault(次要缺页错误):页不在该进程的页表中,但是在内存中,在其他进程的页表中,这一种只需要在进程的页表中简单的更新映射
- major page fault(严重缺页错误):页需要从磁盘调入
- segmentation fault(段错误):程序访问非法地址
大内存页表问题
-
问题:如果内存非常大,那么页表也很大,比如4G的内存,采用4KB的页大小,那么页表将有100w个页表项,因为页可能分散在内存的各个页框,所以需要维护这个包含100w个页表项的页表,并且有多少个进程就有多少个这种页表,非常浪费空间。
-
分级页表
-
原理:采用多级的设置,可以避免始终保持所有的页表在内存中。比如一个进程所需空间进程上下文4M,Data段4M,Stack段4M,总共需要12M,因此虽然虚拟页表还是很大,但是很多都是没有用到的,这些没有用到的页表不应该保存在内存中,而采用两级页表时,只需要保存4个页表,一个顶级页表,一个0-4M、一个4-8M,一个8-12M3个2级页表。顶级页表除了0,其他的页表项Present/absent都会设置为0,每个进程的页表都是独立的
上图a中PT1、PT2分别表示一级页表索引和二级页表索引。上图中一个进程只用3个顶级页表,而其他页表在/不在位被设置为0,当这些不在页表被访问时,会产生一个缺页中断,OS会做处理,这时访问了不该访问的内存。
-
4级页表,4k的页,每级页表用9位索引,最大支持256TB内存
2 9 ∗ 2 9 ∗ 2 9 ∗ 2 9 ∗ 2 12 = 2 48 b y t e s 2^9 * 2^9 * 2^9 * 2^9 * 2^{12} = 2^{48} bytes 2
-