接下来我们介绍虚拟页式存储
那么在前面呢我们已经说过了
虚拟存储它的基本概念是什么样的
它的基本思路是啥样的
那我们把它置换的
交换的这个单位设置为页之后
就变成我们这里的虚拟页式存储
那它的基本思路很简单
就是在页式存储管理的基础上
增加一个请求调页和页面置换算法
那这类的做法呢它具体做起来的时候呢
我们在怎么做呢 它思路是这样的
首先在程序加载的时候它只加载一部分页面
那这个和我们前面的
页式存储管理不一样地方
页式存储管理呢它加载的时候
是把所有的都加载到内存当中
只是它可以实现存储的不连续
你可以找到相应的页面 有空闲页面就足够了
那你这样一来的话
在执行的过程当中它就会出现缺页异常
那在原来的页式管理里头呢
它也会出现异常但不会出现
这里所说的这个缺页
因为我这个进程地址空间里头任何一个页面
都有对应的一个物理页面存在
好 这是跟原来不一样的
好 如果出现这种情况那怎么处理呢
操作系统里头要加一个缺页异常的处理
将相对应的在外存当中页面呢调到内存当中来
并且把相应的页表项进行修改
修改完毕之后以便于我可以重新执行这条指令
那这样的话这条指令就能继续下去了
那随着这个执行的过程呢 那我在内存里呢
只有一部分内存进程的地址空间内容
在内存 但是整个进程它是可以一直这样
良好的运行下去 那关键的问题
就在这个地方有个缺异常的处理服务例程
那这是我们在虚拟页式存储当中的地址转换
如果大家看这张表的话
这和我们前面页式存储的地址转换
是完全一样的 说 这是逻辑地址空间
这是物理地址空间
然后我在某一条指令访问的时候
有一个操作数是页号加页内偏移
然后页号加页内偏移呢通过这边转换之后
到页表 页表找到相应的页表项
如果说是页式存储管理
这里对应的页表项
一定会是有一个物理页号 页帧号
然后找了页帧号呢把它的页内偏移加过来
这就能找到相应的物理内存单元的内容了
好 如果说在前面加上虚拟怎么办呢
加上虚拟之后这个地方呢
你在这个地方就会在页表里加一个
多加标志位 这个标志位呢会表示
我对应的这一页是否在物理内存里头
如果不在这条路就走不下去了
好 这条路走不下去之后呢
执行到这儿呢它就会产生缺页异常
然后 这个缺页异常呢 就会由操作系统来接管
操作系统要做的事情呢是找页把它写好
然后把这个位变成有效
OK 这一件事情就算过去了
这是在虚拟页式存储管理当中的地址转换
我们看到变化呢 从整张图上看变化很小
但实际上这些小点的变化呢会导致很多的修改
好 那这时候一种修改呢是在页表项里头
原来的我们页表项是从以逻辑页号为序号
找到的呢就是物理页帧号
有了这个物理页帧号之后
我就能转换出相应的物理地址来了
但是在虚拟页式之后
虚拟呢我们就会加上一些标志位
这是在虚拟存储管理里头
需要用到的几个标志位
分别的含义是什么呢
首先第一个有一个叫驻留位
它是表示该页面是否在内存当中
那如果说是一 表示在内存当中这时候呢
对应过来一定可以找到它的页帧号
那可以转换成实实在在的物理内存单元的地址
好 如果它是零 表示这一页呢在外存里头
那这时候就会导致缺页
那导致缺页之后呢
就会来修改这些标志位
好 这是第一个标志
第二个标志是修改位
表示这一页在物理内存当中有的这一页
这必须是驻留位有效的情况下
好这一页如果被修改过
那这时候呢它会有什么变化呢
如果说我想把这一页淘汰放到外存里头去
那么这时候我必须把内存当中修改的内容
写回到外存当中
如果说这个地方没有修改过
那这时候呢对应在外存单元里头有相应的内容
那这时候我在替换的时候
置换的时候我只需要把这一页作废就行了
这是修改位 然后还有一个呢是访问位
表示这一页在过去一段时间里头
是否被访问过
因为我们在虚拟页式存储管理里头
它需要有一个置换算法把不常用的页面
置换到外存当中去
那么哪些常用哪些不常用呢
就是靠这个访问位来进行统计
访问位访问过它是一 没访问过它是零
那这样的话它就在一定程度上
近似统计出来这一页是否被经常访问
一表示经常访问 零表示不经常访问
还有一个呢保护位
这个保护位是用来表示这一页允许访问的方式
你比如说 只读 可读 可写 可执行等等
这样一些信息 好 那有了前面地址转换
和页表上的修改这件事情从道理上来说
我的虚拟页式存储管理就算说清楚了
那么下面我们先通过一个例子
来说明一下这个过程
假定我有一个16位的逻辑地址
然后这个时候呢它的逻辑地址空间呢是64K
然后物理内存我只有32K
页面大小是4K 好 这时候我划分出来的情况呢
这是逻辑地址空间 这是物理地址空间
好 那么这时候说我在这里做映射怎么做呢
我哪些映射到物理内存里头来的
我在这里有相应的编号 没有映射过来的
我的简化表是这里写的是X
好 然后这样以来的话
它们就建立一张表 对应过来这里写的是几7
对应到物理单元的帧号是7
好 那这样的话我这里的8个物理页面
和16个逻辑页面之间
有一半有对应关系 这是在页表项里有的
好 那么这时候呢这里的X
隐含着你的页表项里头的驻留位是零
然后这个7呢隐含着你的驻留位是1
那这个对应过来是驻留位的表示
好 那么在这种情况下我们看我执行一条指令
MOV把指定存储单元内容移到寄存器里头去
好 那这时候说我在这边看对应的这一页
在这个地方对应过来到这个地方 好 它是有的
那这一条它是正常能访问过来
好 我们再来一条指令
我这个MOV 32到这个地方就是x
不存在 好 这时候会产生什么情况
这地方就是缺页
缺页之后我就需要把现在在内存里某一页去掉
然后把它对应内容写到内存里头
并且改这一项
OK我后面事情就可以做了
以我们现在最常用的X86 32的
CPU的页表结构来作为实例
那么在32位的X86系统当中呢
它有12位的页内偏移
然后有2个10位的二级页表项
这样的话是32位地址
然后物理地址呢也是32位的
那20位呢是物理页帧号
好 然后这时候呢 它使用一个二级页表
那这是它页表结构
然后页表项的起始地址呢是CR3
CPU里一个寄存器指出来
然后从这儿呢
我一个页表项占4字节 那一页由于是32位的
好 那占4个字节呢 那么这4K为一页
那这时候呢这12位是4K 4K为一页
一页里头有1024项 1024个页表项
那么正好对应着我这里的10位
好 那这是第一级 然后第二级 这是它的页表
那我们的地址转换怎么过来呢
先是一级页表项里头的页号到这儿
作为它的偏移找到相应的页表项
一级页表项 好 这个页表项里头它有一个
第二级页表项的物理页号
好 然后这个时候呢
再加上你第二级的页号 好 那从这儿呢
第二级页表项里头呢
以它页号作为偏移找到相应的页表项
那这时候就是你实实在在要访问的
物理页面的物理帧号
好 那这个帧号呢 和你的偏移搁在一起
把页内偏移加在一起这得到你的物理地址
那么这是在这个结构当中它的页表的结构
这和我们前面讲到的页式存储呢
是完全一样的 那它变化地方在哪呢
变化地方是页表项里头的东西
那这地方是X86 32在以4K为页面大小的时候
它的页表项的定义格式 那我们在这里关心的
这是20位的物理页帧号
这个没有什么变化
我们需要关心后面这一段的标志
那我们刚才在逻辑示意当中呢
已经看到有几个标志
在这儿呢实际上看到的标志更多
那需要这几个是能对上的驻留位 可写位
这是相当于权限 好 在这里头
我们可能在前面没注意到就是用户态标志U
实际上这表示我这个页表项
是否可以在用户态访问
那在内核地址空间呢
只能有内核的状态的时候才能访问
那这是一个权限的控制
好 然后访问位 修改位
然后跟我们前面不一样的地方有几个
一个是保留位 那在这里头呢这标志位没用完
它总会留有一些保留
原因在于我们如果在32位的X86系统当中
这个页表项是好用的
但实际上呢我们在实际的系统当中
它的物理地址空间呢 它是在不断变化的
好 你比如说我32位的系统
它最大的物理内存地址空间呢是4个G
实际上我们现在用到的一些32位的系统
它已经不是这个4个G了
大于4个G怎么办 好 那这个时候
相应的页表项就得跟着这个在变
那这些呢都是为了后续的这些改动
留有空间的 如果说你去看
实际的因特尔的手册
那么这里页表项结构呢有很多种
那么它们很多是兼容的
但是这些变化都从这儿出来的
然后还有两个是这个地方
就是缓存是否有效 是否写通
实际上这里说的呢是在内存和CPU之间
有一个高速缓存
这个缓存呢我在读写数据的时候
会把写出的数据先写到缓存里头
然后高速缓存再慢慢地把它写到内存里头
那如果说我要有一些时效性的操作
比如说对I/O端口的操作
那这种缓存是会影响我的语意的
好 那这儿是有这个标志来做控制
然后再有一些呢我在读的时候
是否高速缓存有效
如果说你前面读了一次 那这时候呢
我后面再读的时候我可以直接
从高速缓存里得到这个数据
但实际上呢如果说这个数据它是时时在变的
好 你第一次I/O端口里读到的数据
第二次再读的时候你必须要从I/O端口里
实实在在去读 那么这时候呢
这些标志位都会影响到它的行为
所以从这儿来看呢
我们看到这个基本的原理里的虚拟页式存储
和我们实际系统当中的还是会有一些差别
这些差别转换到我们实际的
实验系统代码里头代码里头
这些差别就会导致我们代码会有很大的变化