虚拟存储器作为计算机系统中重要概念,很多操作系统书籍都已经详细地阐述了具体技术理论。但是,要真正地理解和明白,其实还是有一定难度的。本文将以linux 虚拟存储器系统来阐述虚拟存储器系统的相关知识,如果本人理解有误,希望大家指正。
1、 linux 可执行文件的格式(ELF),
计算机系统中,虚拟存储器肯定与运行的程序(即进程)息息相关。可执行程序是文件系统中的一个可执行文件,因此首先将可执行文件的格式ELF简要介绍下。本文讲述的可执行文件,并不是所有linux 下面具有执行权限的文件,而是利用C/C++ 语言编写,C/C++ 编译器生成的ELF 格式的可执行文件。比如,利用gcc –o hello hello.c 程序生成的hello 文件就是ELF 格式的。ELF 格式如下图所示(摘取自深入计算机系统):
可执行文件被划分为段,以段结构进行组织,每一段都对应不同的内容。其中.text 段就是程序代码经过编译以后形成的。.rodata 就是程序中的只读数据,.data 段是程序中声明的全局的可变变量等。
2、运行可执行目标文件
当在shell 窗口敲入如下命令:> ./hello 时,操作系统就会创建一个进程,有自己的虚拟地址空间(其实就是一个地址范围,并且每个进程的范围都一样),操作系统会将该进程相关信息与可执行文件进行关联。关联过程如下:
左边的图片可以理解为一个linux 进程的虚拟存储器,它的虚拟地址空间(即计算机指令的地址范围)为:0-2的32次方(64位机器就是2的64次方),这个虚拟地址空间范围告诉大家可以去使用这个空间的任何地址,但是一般一个程序只会使用其中一部分。既然是“虚拟”,说明它不是真实存在的,是逻辑上的概念,用于说明计算机中如何去组织这些信息。在计算机中不存在实际空间存放图片中左边这样的结构。操作系统是这样实现的:利用数据结构分别记录.text 段,.data段等的相关信息,当程序执行的时候,再利用这些记录的信息去将可执行文件的信息加载到内存中进行运行(具体参考深入理解计算机系统的9.7.2)。
a、可执行文件中的text 段的内容如何知道对应到左边的哪个地址范围之内?
这是因为可执行文件中的text段中有虚拟地址信息。所有进程能使用的虚拟地址空间范围都是一样的(0-2的32次方),所有可执行程序的text 段中的地址完全有可能相同。它通过这些虚拟地址信息,映射到进程的虚拟地址空间的相应范围,实际的实现过程就是在数据结构中记录这个地址范围。
b、为什么同样的地址在内存中不会产生冲突呢?
这是因为这些地址都是虚拟存储器中的地址,程序在运行的过程中,操作系统通过一定的地址翻译机制(参考深入理解计算机系统9.6节)将虚拟地址翻译为实际内存中的地址。
3、虚拟内存(linux中叫交换空间)
a、内存才256M,为什么运行比256M 大的可执行文件都能运行呢?
操作系统运行程序的时候,并不是将所有的信息都加载到内存中,它是按需加载,先加载程序现在运行所需的代码和数据到内存中,当程序运行一段时间后,如果需要别的代码和数据时,操作系统会将该进程目前在内存的某一部分代码换出来存储在磁盘的某个空间(也就是虚拟内存或交换空间,注意这个空间并不是可执行文件的硬盘空间),并将所需的代码加载到内存中。这种方式就解决了程序比内存大的情况,而刚才的那个交换空间默默地作为内存的扩展,因此称为虚拟内存。
4、参考文献
a、Playing with Virtual Memory (这篇文章从程序的角度讲解了虚拟内存)
翻译地址:http://blog.nosqlfan.com/html/2956.html
b、Computer Systems-A Programmer’s Perspective(深入理解计算机系统第二版,主要参考第7章和第9章)–很好的一本书,强烈推荐
看完这篇文档,大家可能还是云里雾里,希望大家留言进行交流!