首先我们来一个概念
虚拟内存,虚拟内存是一种内存管理技术,它会使程序自己认为自己拥有一块很大且连续的内存,然而,这个程序在内存中不是连续的,并且有些还会在磁盘上,在需要时进行数据交换
难以实现的物理寻址
我们把内存可以看成一个一维数组,那么这个数组的下标就是内存的物理地址,CPU用内存的物理地址来定位他想获取的内存块(数组中的内容),我们把这种方式称为物理寻址。
如下图:
我们都知道,我们写的程序经过编译器编译成机器级语言后会被保存到文件中,当我们要运行它的时候,操作系统会将其加载到内存中并交给CPU去处理,CPU只处理一条条的指令。设想一下,如果内存中有一个程序,CPU通过系统总线去和内存中的指令和数据进行交互时,采用物理寻址将非常自然、方便,但是如果是两个程序或者多个程序会出现怎样的情况?
我们会看到两个程序中都有一条指令 mov eax (100),注意,这里的100是相对于正在运行的进程而言(单核),如果直接使用物理地址,那么就得分析每一个进程中的每一条指令,看看哪一个指令是操作内存的,并且要知道该进程的基值地址,然后把该指令中的位置(偏移量)加上该进程的基地址,分析指令是非常麻烦的,不容易实现,所以,我们引入了虚拟寻址(逻辑地址),如下图:
我们从图中可以看到,在使用虚拟寻址时(用逻辑地址),CPU会生成一个虚拟地址(逻辑地址),用这个虚拟地址来访问主存时需要经过一个MMU(内存管理单元)来对这个虚拟地址进行翻译,把这个虚拟地址变为真正的物理地址,对于每一个进程而言,它在执行的时候基址寄存器中的值是不一样的,比如上面的程序1,它的基址寄存器中的值为0,而对于程序2 寄存器中的值1000,这样一来CPU就不用分析当前进程中的指令了,当CPU执行一个指令的时候,它就认为所有关于内存地址的地址都是虚拟地址,然后发给MMU,经过MMU后就会将其翻译成真实的地址,最后,内存通过系统总线把数据给CPU传了过去。这里注意一个问题:MMU怎么知道当前进程的基地址?这是因为操作系统知道每一个进程的基地址,MMU(内存管理单元)硬件会利用放在主存中的查询表来动态地翻译虚拟地址,该表的内容是由操作系统管理的,也就是说,在进程进行切换的时候,这个基值寄存器中的值是会发生改变的。
那虚拟地址到底长什么样?请看下图:
每一个进程都有一个虚拟地址空间,而且结构非常相似
这样看起来一切顺利,但事实并非如此,因为我们的电脑内存很是有限,有些应用程序它需要很大的内存来运行它,这样一来,有时内存就不够用了,那应该怎样解决呢?
我们想到了局部性原理(上帝的法则),局部性原理有两个:
① 时间局部性: 意思是说,我电脑中的程序某一条指令在使用完之后,在不久的将来有很大可能再次地使用它
② 空间局部性: 这个是说,我电脑中的某一块内存在使用时,在不久的将来会使用内存地址相近的一块内存区域
所以我们决定,我们把应用程序代码不全部加载到内存中去,只是加载一小部分
接下来我们了解几个新的概念:
虚拟页和物理页
虚拟存储器系统把虚拟存储器分割成大小固定的块,这一块一块的存储器中的内容我们称为虚拟页[虚拟页不是真实存在的,而是逻辑上的],同样的道理,我们把物理存储器分割成物理页(内存中)
拥有虚拟页地址和物理页地址信息的页表
页表就是一个存放页表条目(Page Table Entry,PTE)的数组,里面存放了若干个页表条目,那么什么是页表条目呢?页表条目其实就是描述虚拟页信息的一块内存[物理](也可以说成数据结构[逻辑])如下图
我们可以简单地认为页表条目是由一个有效位和一个n位地址字段组成,有效位表明了该虚拟页当前是否被缓存到内存中了
了解了页表,我们再来看看物理页、虚拟页和页表之间的一个关系,虚拟页是虚拟存储系统把一个程序的虚拟地址空间划分了若干个虚拟页,(注意,这个虚拟页不是真正存在的东西),虚拟页有三种情况,一种是未分配的,不占用内存空间,第二种是未缓存的,也就是以存储在磁盘上的形式存在,还有一种是缓存的,也就是以存储在内存中的形式存在,接下来我门来看一个图
从这个图中我们可以看到,页表条目其实就是一个虚拟页的描述,它描述了虚拟页是否被缓存在内存中(有效位),以及虚拟页的存储位置(未分配的为null,缓存了的指向内存中物理页的地址,未缓存的指向磁盘中虚拟页的位置)
下来我们看看这个逻辑地址是如何工作的
在页面命中时,CPU硬件执行的步骤为:
第一步:处理器生成一个虚拟地址(VA),并把它传送给MMU
第二步:MMU生成页表条目的地址(PTEA),请求内存中的页表,让它给自己返回一个页表条目(PTE)
第三步:MMU构造物理地址(PA),然后把这这个物理地址传给内存(这时候是真实的物理地址),请求物理内存中的数据
第四步:内存返回所请求的数据给处理器
过程如下图:
这里我们不讨论页面不命中的时候
我们来看一个总图,来总结一下今天所提到的知识,看看到底在整个计算机中虚拟存储技术是如何工作的
到这里,我们可以发现,虚拟内存技术的核心就是利用了局部性原理,把所要运行的进程中的数据不全部加载到内存中执行,而是加载一部分,当CPU在请求页表时,发现页表中的页表条目中的有效位为0但是被虚拟存储系统分配了的虚拟页时,就会把这个虚拟页从磁盘中调度到内存中(往往磁盘中的数据不常用,而在内存中的物理页的数据是频繁使用的数据),这样一来,我们就实现了多个进程同时加载到内存中并且还占用不是很多的内存的效果了
本文参考《深入理解计算系统》和刘老师的讲课