操作系统之虚拟内存的理解

论坛 期权论坛 编程之家     
选择匿名的用户   2021-6-2 20:48   2117   0

1、问题及基本概念

对于现代操作系统而言,进程是基本的管理对象。例如在windows中,打开一个word,就启动了一个进程,打开第二个word,便又启动了一新进程,两者

相独立互不妨碍(编辑word 1时不会对word 2造成任何影响,反之亦然,要知道它们运行的可是同一个程序啊!),每个程序运行时都好像独占整个内存空间,操作系统制造的这种“幻象”便是虚拟内存,那么它究竟是如何实现的呢?

2、相关知识

现在是最好的时代,因为今天我们站在了多年技术积累的更高层从而创造了更大的生产力(我们有功能强大完善的操作系统,各种丰富的开发、调试工具来开发复杂的产品)。现在是最坏的时代,我们因站的太高对曾经发生的一切都浑然不知而对技术最后展现的结果增添了一道又一道迷障(对于上述技术背后的点点滴滴都不明了)。现在试图从计算机软硬件发展的历史逐步求索我们的问题。

最初的计算机并没有操作系统(可以类比目前的单片机裸机系统),也没有保护模式的概念,计算机能做的便是CPU直接从内存(物理)地址处一条条取指令执行而已。此时的计算机同时只有一个程序在运行,如下图所示。

人们自然不满足于此。比如在计算一个耗时的科研程序时,在计算结果出来之前人们不希望只是干等着,而能够同时做其它事情比如和其他计算机用户聊天等,于是多任务操作系统出现了。此时的加载程序,也逐渐演化为了调度程序---它可以使CPU在多个进程中切换运行(此时已具备了操作系统的最基本功能,类似于嵌入式的ucos2实时内核)。现分析一种情形:一个程序编译完成(其编译地址空间为0x0000~0x0200),假设该程序先后启动了两次,第一次被加载到0000处,为了与第一个进程隔离,加载器将第二个进程加载到了0x0400处。那么,由于第一个进程的加载地址与编译地址空间一致,故可以直接运行;第二个进程的加载地址与编译地址不同,则程序代码区域2的内存映像必须对所有引用绝对内存地址的指令做相应修改,例如第0x400处的指令,[0x100]内存地址处的操作数0x32实际上在0x500处,此时加载器必须将[0x100]改为[0x500]后,第二个进程才能正常运行。

仔细分析,以上有两个问题。一是程序的运行(加载)地址不确定,往往与编译地址不同,需要加载程序在运行前修改内存代码中所有直接内存地址。二是不同程序共用整个物理内存空间,单个程序可以向任意内存地址读写数据,这可能破坏其他程序代码数据,严重影响整个系统的稳定性和安全性。此时就必须得到新硬件(MMU、内存管理单元)的额外支持了。新的系统运行原理如图所示。

由图可以看到,每个进程都有一份内存映射表(该表进程不可见,由操作系统维护),每次cpu执行进程的一条地址访问指令,则mmu硬件自动将指令的地址自动转换到相应的物理地址,不同的进程访问的不同地址被转换到不同的物理地址,从而隔离了不同的进程,实现了虚拟内存。现在我们可以回答文章开头的问题了:首先我们的word程序被编译为可执行代码,编译器假设程序被加载到从0开始的线性内存空间中,生成了大小为0x200的代码(包括数据)。第一次打开word 1时,操作系统将程序代码加载到了上图的区域1,第二次打开word 2则加载到了区域2,操作系统根据不同的加载地址分别对两个进程设置程序地址和物理地址的映射表。这样当程序运行时,由MMU硬件自动根据映射表实现程序地址到物理地址的转换,该过程对CPU完全是透明的。所以,一切本质上都是由于MMU映射的存在,使任意进程失去了直接访问任意物理地址的能力,从而达到了不同进程间保护和隔离的目的。

3、总结

如上,关于虚拟内存在进程间隔离的原理已经说完了。不过,广义的虚拟内存概念还包括磁盘空间到虚拟内存空间映射的知识,这一点本文就不展开了。

分享到 :
0 人收藏
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

积分:3875789
帖子:775174
精华:0
期权论坛 期权论坛
发布
内容

下载期权论坛手机APP