虚拟内存是什么(虚拟内存怎么清理)

程序编译后,就成了可执行文件 。可执行文件主要包括代码和数据 。代码是只读的,而数据是可读和可写的 。
可执行文件由操作系统加载到内存中,并交给CPU执行 。现在问题来了,CPU如何访问代码和数据?,参观的方式经历了四个阶段:
1.直接存取
2.段基址段偏移地址
3.段选择分段偏移地址
4.虚拟地址
现代操作系统采用虚拟地址,这也是本文的重点 。而虚拟地址是从1~3个阶段发展而来的,所以需要详细阐述1~3种访问方式 。
直接访问直接访问很好理解 。程序编译后,生成一个可执行文件 。编译器为每行数据和代码分配一个唯一的地址,如下图所示 。
可执行文件
如上图所示,可执行文件中1000到1024之间的地址被加载到内存中,内存的地址也在1000到1024之间 。可执行文件中分配的唯一地址是内存中的物理地址,这称为直接访问 。直接访问很简单,没有任何曲折 。
当时有很多问题,比如同一个可执行文件不能同时执行,它们的物理地址是一样的,它们是冲突的,所以必须一个接一个 。此外,可执行文件的物理地址是固定的,如果它想在其他物理地址上运行,就必须重新编译以生成新的物理地址 。
可见,直接定位是计算机早期发展的产物 。前期没有那么多程序要运行,程序都是一个一个执行的 。所以前期的这个定位还是比较简单直接高效的 。
段基址 段偏移地址随着多任务的出现,内存中有许多程序同时运行 。虽然直接定位把每个不同的程序放在不同的内存段勉强够用,但是一个可执行文件不可能同时运行多个程序 。此外,程序必须运行在固定的物理地址,这大大降低了灵活性,使调度非常麻烦 。因此,CPU设计者和操作系统开发者发明了段基址和段偏移地址 。
Inter 8086处理器采用这种定位方式 。我们知道可执行文件主要分为数据段和内存段,如下图所示 。
从上图红色部分可以看出,0、4、8是相对于数据段的偏移地址,0、4、8、12是相对于代码段的偏移地址 。
在可执行文件中,一个段的偏移地址是固定的,无论可执行文件加载到内存的什么地方,这个偏移地址都是固定的 。
当可执行文件加载到内存中时,首先在内存中分配一个数据段和一个代码段 。理论上,这两个部分不需要彼此相邻 。通常,代码段和数据段是相邻的 。代码段和数据段在内存中都有一个起始地址,称为段基址 。这个段基址放在段寄存器中,比如代码段基址放在CS寄存器中,数据段基址放在DS寄存器中 。当然,还有其他段,如堆栈段 。开始时,堆栈大小为0 。随着程序进出栈,这个栈段不断扩大 。当然我们主要说的是数据段和代码段,栈段就简单接管了 。
假设可执行文件被加载到内存中,如下图所示
如上图所示,代码段以0x0060000为起始地址在内存中布局,数据段以0x00601000为起始地址在内存中布局 。
当CPU开始执行代码段的第一条指令时,会将代码段的起始地址放入段寄存器,此时CS代码段寄存器存储0x00600000,然后从起始地址开始执行第一条代码指令 。此时它把代码指令的偏移地址放入IP寄存器,该寄存器存储0,于是CPU通过CS:IP定位一条代码指令,如下图所示 。
定位指令
当CPU执行0x00600000的代码指令时,指令为MOV AX,[0],表示地址0的数据存放在AX寄存器中,这个0就是数据段的偏移地址 。此时CPU会将数据段的起始地址加入DS段寄存器,然后定位数据段寄存器的偏移地址,即0x00601000 0=0x00601000,到数据123 。
定位器数据
以上过程就是【段基址段偏移地址】的定位方法 。将起始地址添加到寄存器中的原因是,当后续执行指令或数据时,可以直接从寄存器中获取,以加快CPU的执行速度 。
段选择子 段偏移地址段选择子段偏移地址和段基址之间有一些相似之处 。之所以采用段选子段偏移地址,主要是为了安全 。在段基偏移地址的原始模式下,程序员可以直接跳转到其他代码段和数据段,没有任何限制 。安全性完全取决于程序员的职业道德和水平,所以CPU设计师发明了段选择子段偏移地址 。
段选择器偏移地址中的段选择器可以认为是一个索引,它指向全局段描述符表中的一个项,这个表存储在内存中,它的起始地址存储在全局段描述符寄存器中 。
全局段描述符表有许多段描述符,每个段描述符占用8个字节 。该段描述符包括段基址和一些安全相关的描述信息,如段的可读、可写、可执行和大小 。
段选择器存储在段寄存器中,共有16位,其中高13位是全局段描述表的索引 。


推荐阅读