转载自公众号:在下小神仙
为什么要有虚拟内存机制?
在早期的计算机中,是没有虚拟内存的概念的。
我们要运行一个程序,会把程序全部装入内存,然后运行。
当运行多个程序时,经常会出现以下问题:
-
进程地址空间不隔离,没有权限保护。
由于程序都是直接访问物理内存,所以一个进程可以修改其他进程的内存数据,
甚至修改内核地址空间中的数据。
-
内存使用效率低
当内存空间不足时,要将其他程序暂时拷贝到硬盘,然后将新的程序装入内存运行。
由于大量的数据装入装出,内存使用效率会十分低下。
-
程序运行的地址不确定
因为内存地址是随机分配的,所以程序运行的地址也是不确定的。
上面的文字已经很通俗了,但是如果大家还是没有看懂的话,没关系,小神仙来举几个例子。
小北和小神仙是一个班级里面的两名同学。
小神仙是班上的第一名,小北是倒数第一名。
老师叫小北和小神仙上去做数学题。
小神仙飞速写完正确答案,坐回了座位,没想到小北嫉妒小神仙的聪明才智,在小神仙回到座位之后改了小神仙的回答。
小黑板就是我们计算机的内存,小北呢,就是那个修改其他进程数据的进程。
老师又叫了几个小朋友上去写题目,这个时候黑板不够写了,老师看小北苦思冥想也没写出什么来。只好把小北先叫下来, 让其他同学先回答。这就属于内存空间不足。
小朋友们上去的时候老师并没有指定区域,所以小伙伴们是看着那块黑板空就选哪块写,这个时候也就是我们说的程序运行的地址是不确定的。
为了有效的管理计算机的存储器并且减少像小北这种胡乱修改别人的答案的情况,(即减少出错,现代系统就提供了对内存的一种抽象概念,叫做虚拟内存(VM)。
讲了这么久,那虚拟内存到底长什么样呀?
给大家看下,就长下面这个样子。
其中,Linux内核把虚拟地址空间分为两部分:用户进程空间,内核进程空间。
对于32位系统,寻址指针为4字节,对应的虚拟地址空间为0-2^32,即0-4G。
对于64位系统,寻址指针为8字节,对应的虚拟地址空间为0-2^64,即0-16G。
要注意的是,这个地址空间是虚拟的,并非实际存在的。
大家每次创建一个进程的时候,操作系统都会给进程分配这样的一个虚拟内存。
虚拟内存还有一个什么好处呢?
那就是能跑比物理内存大的应用程序。
在实际的应用中,如果需要运行的应用程序比较小,所需内存容量小于计算机实际所配置的内存空间,自然不会出什么问题。
但是,目前很多的应用程序都比较大,计算机实际所配置的内存空间无法满足。
实践和研究都证明:一个应用程序总是逐段被运行的,而且在一段时间内会稳定运行在某一段程序里。
这也就出现了一个方法:如下图所示,把要运行的那一段程序从辅存复制到内存中来运行,而其他暂时不运行的程序段就让它仍然留在辅存。
当需要执行另一端尚未在内存的程序段(如程序段2),如下图所示,就可以把内存中程序段1的副本复制回辅存,在内存腾出必要的空间后,再把辅存中的程序段2复制到内存空间来执行即可:
在计算机技术中,把内存中的程序段复制回辅存的做法叫做“换出”,而把辅存中程序段映射到内存的做法叫做“换入”。
经过不断有目的的换入和换出,处理器就可以运行一个大于实际物理内存的应用程序了。
或者说,处理器似乎是拥有了一个大于实际物理内存的内存空间。
虚拟内存如何和物理内存联系起来的呢?
既然虚拟内存是一个虚拟的概念。
也就表名了虚拟地址不能真正的存放数据。
数据在真正读写的时候,是对真实的地址空间进行读写的。
处理器运算器和应用程序设计人员看到的只是虚拟内存空间和虚拟地址,而处理器片外的地址总线看到的只是物理地址空间和物理地址。
将虚拟地址转换成物理地址的任务叫 【地址翻译】。
虚拟内存的地址如何转成真实地址。中间需要一个转换(映射)的机制。
这个东西我们叫做 MMU (存储器管理单元)。
MMU 把虚拟地址转化为实际物理地址的依据。
记录表与存储管理单元MMU的作用如下图所示:
到这里, 相信大家应该理解虚拟内存和物理内存是通过映射记录来建立联系的。
那大家可以再思考一个问题,映射记录里面存放的是什么值呢?
我们知道计算机的存储单元是字节,如果按照存储单元来管理内存,那也就意味着这个映射表会非常的大。
以存储单元为单位来管理显然不现实。
因此Linux把虚存空间分成若干个大小相等的存储分区,Linux把这样的分区叫做页。
在内存管理时,页是地址空间的最小单位。
为了换入、换出的方便,物理内存也就按也得大小分成若干个块。
由于物理内存中的块空间是用来容纳虚存页的容器,所以物理内存中的块叫做页框。
页与页框是Linux实现虚拟内存技术的基础。
虚拟内存的页、物理内存的页框及页表
在Linux中,页与页框的大小一般为4KB。
当然,根据系统和应用的不同,页与页框的大小也可有所变化。
物理内存和虚拟内存被分成了页框与页之后,其存储单元原来的地址都被自然地分成了两段,并且这两段各自代表着不同的意义:
高位段分别叫做页框码和页码,它们是识别页框和页的编码;
低位段分别叫做页框偏移量和页内偏移量,它们是存储单元在页框和页内的地址编码。
下图就是两段虚拟内存和物理内存分页之后的情况:
为了使系统可以正确的访问虚存页在对应页框中的映像,在把一个页映射到某个页框上的同时,就必须把页码和存放该页映像的页框码填入一个叫做页表的表项中。
这个页表就是之前提到的映射记录表。
一个页表的示意图如下所示:
页模式下,虚拟地址、物理地址转换关系的示意图如下所示:
也就是说:处理器遇到的地址都是虚拟地址。
虚拟地址和物理地址都分成页码(页框码)和偏移值两部分。
在由虚拟地址转化成物理地址的过程中,偏移值不变。
而页码和页框码之间的映射就在一个映射记录表——页表中。
虚拟内存带来的好处
-
虚拟内存管理可以控制物理内存的访问权限
访问的虚拟页若没有读写权限,则触发一个保护异常,终止进程。
-
虚拟内存让每个进程有独立的地址空间
对于私有区域来说,当不同进程对该区域做修改时,会触发写时拷贝,为新进程维护私有的虚拟地址空间。
-
虚拟地址到物理地址的映射会给分配和释放内存带来方便。
物理内存不连续的地址,可映射到连续的虚拟内存地址。
-
内存效率高
使用了页面调度,不会造成大量的数据装入装出。