虚拟内存介绍及MMU工作原理(一)

在linux,包括很多操作系统中,虚拟内存的概念十分重要。在使用windows的过程中,我们经常会遇到“虚拟内存不足”的提示,linux中有个所谓的swap分区,包括linux和uClinux的最大区别,就是有没有MMU。那么,究竟什么是虚拟内存?什么是MMU?他们的作用分别是什么?今天的这篇文章就来普及一下这个问题。
这篇文章主要参考了以下两个网页:
http://tldp.org/LDP/tlk/mm/memory.html
http://blog.csdn.net/xie376450483/article/details/5728772

一、什么是虚拟内存
在我们嵌入式的编程(以PIC为例)中,我们是没有虚拟内存的概念的,我们现在使用的PIC24FJ64GA002的片子,RAM和ROM都只有几K而已,也没有所谓的虚拟内存。
但是,当我们需要运行一个很大的程序的时候,尤其是这个游戏需要很牛X的图形界面的时候,内存肯定会消耗很大。比如大家常玩的魔兽争霸,有没有想过,这样一个准3D的程序,能够在256M内存的电脑上运行,好牛X啊。
其实,很多程序用到了非常大的内存(至少远远大于我们物理上实际的内存),包括linux中,每个进程都有3G的独立地址空间(而不是4G,感谢邢大天同学纠正我的理解错误)。那么,物理上既然没有这么多内存,我们就需要虚拟出一部分内存来——这部分虚拟的内存不是在RAM中,而是在你的外部存储器上(比如ROM,硬盘等等)。虚拟出来的这些东东,就叫做虚拟内存。
举个例子。如果我们使用的是32位的CPU,那么按道理来说,最大的能够访问的地址空间就是2的32次方,也就是 0~0xFFFFFFFF (4G)。换句话说,理论上,一个程序能够访问这么大的空间。电脑上的CPU很多是32位的,但是我们电脑的内存一般都是1-2G。多出来的那些内存怎么办?没错,这就要用到虚拟内存。
当然,事实并没有上面说的这么简单。并不是说,电脑的物理内存不够用,就把磁盘中划出一部分来当做虚拟内存——事实上,每个进程在运行的时候,都有3G的独立地址空间,这个地址空间都叫做虚拟内存。然而,虚拟内存的一部分,可以位于真正的RAM中;另一部分,可以位于外部磁盘,或者外部FLASH中。
那么,如何让0-3G的空间一部分在RAM中,一部分在其他地方呢?

二、虚拟内存运作的流程
再来看这样一个例子:大家都知道,linux中,每个进程能够分配到3G的独立内存空间。(事实上,0-3G为用户的进程空间,3G到4G是内核空间)。那么,假如我运行了一个程序,里面用到了1G的内存空间,而我板子上只有256M的RAM,操作系统会这样做:
首先,把实际的物理内存(256M)按照每4K为一个单元标号,每一个单元称为“页”。同时,把0-3G的虚拟内存也按照每4K为一个单元(页)标号。
其次,需要介绍一个规律:科学家们发现,在汇编语言的级别,如果一个地方的数据被用到,那么该数据附近的数据在接下来被用到的概率就很大;同时,如果一个地方的命令被执行,那么该命令附近的命令在接下来被执行的概率也比较大。
第三,有一个专门的数据结构来管理一种对应关系:某一页的虚拟内存可能要被用到,那么就需要找寻到该页在真正内存中的页码。该数据结构就是用来存放虚拟内存-物理内存的页的对应关系的,称为Page Tables(页表)。

那么现在的过程就是如下图:
虚拟内存介绍及MMU工作原理(一)_第1张图片
当我的某个进程(X)开始运行的时候,首先访问图中VPFN0指向的数据。通过页表,发现该部分的虚拟内存实际上是位于PFN0区域(物理内存的开始)。那么,程序实际上访问的就是物理内存的PFN0区域。程序继续执行,需要访问VPFN3地方的数据,根据页表这个数据结构,对应的是PFN4的物理区域,于是就对PFN4进行操作。
同时,当另外一个进程(Y)开始运行的时候,首先访问VPFN1指向的数据。通过页表,发现对应物理内存中PFN4的数据。随后访问到VPFN6中的数据,根据页表,对应PFN2区域。
由此,我们也可以得出一个结论:物理内存的地址,和虚拟内存的地址实际上没什么关系。
另外一个结论是,不同的进程可能会被分配同一个物理内存(这就是传说中的共享内存,这样两个进程之间就能够通信了)
第三个结论是,不同的进程的虚拟内存,其对应的物理内存实际上没有多大关系。

三、虚拟内存流程中的问题
如果事情都像刚刚说的这么顺利,我们的工作似乎都完成了。遗憾的是,事实往往没有这么美好。最根本的一个问题是:物理内存就256M,而虚拟内存有3G。多出来的内存,怎么办?
这个问题的答案很长,今天的帖子先做一些提示,具体的机制下个周再发个帖子详细说明。
问题一,多出来的内存都是放在哪里?以什么样的形式来存在?
问题二、系统如何判断内存中的数据,哪些应该位于物理内存中,哪些应该位于外部存储器中(标准是什么)?如何将数据从物理内存中转移到外部存储器中?
问题三、如果程序用到了虚拟内存中的某些数据,这些数据没有在物理内存中,而是在外部存储器中,应该怎么办(如何知道数据位于哪里,并且如何读入数据)?

你可能感兴趣的:(虚拟内存介绍及MMU工作原理(一))