编译器编译出来的线性地址空间,在虚拟内存技术的环境下,通常被称为虚拟地址空间。这两者的概念在虚拟内存系统中本质上是相同的,只是由于环境和使用场景的不同,名称有所区别。具体来说,以下几点解释了这种关系:
1. 线性地址空间 vs. 虚拟地址空间
线性地址空间:编译器在生成程序时,会为程序分配一个逻辑上连续的地址空间,这个地址空间通常是线性的,也就是从起始地址到结束地址的空间是连续的。这些地址空间用于访问程序的代码段、数据段、堆和栈等。这种线性地址空间并不对应物理内存中的实际位置,只是逻辑上的地址。
虚拟地址空间:在虚拟内存系统中,操作系统为每个进程分配一个独立的虚拟地址空间,这个空间同样是线性连续的。这就是编译器生成的线性地址空间在虚拟内存环境下的实际表现。
因此,在虚拟内存系统中,编译器生成的线性地址空间就是虚拟地址空间,只是不同的叫法而已。虚拟地址空间的大小和范围是操作系统为每个进程提供的,编译器生成的线性地址空间在程序运行时,映射到这个虚拟地址空间。
2. 逻辑地址、线性地址和虚拟地址
在有虚拟内存技术的系统中,这些概念通常可以互换使用:
- 逻辑地址:通常指编译器生成的程序地址,它是程序运行时使用的地址空间。逻辑地址是线性的,并且相对于程序的起始位置。
- 线性地址:逻辑地址空间的一种特定形式,通常是连续的,便于程序在执行时进行内存管理。在线性地址空间中,程序可以认为自己在操作一块连续的内存。
- 虚拟地址:虚拟内存系统中,进程使用的地址空间就是虚拟地址空间。虚拟地址是逻辑地址和线性地址的实现方式,在底层通过页表映射到物理内存。
实际上,这些地址在程序运行时都被认为是虚拟地址,因为它们并不直接对应物理内存,而是通过页表机制映射到物理内存。
3. 虚拟地址空间的结构
在虚拟内存环境下,操作系统为每个进程分配的虚拟地址空间一般是线性的,分为不同的段,如:
- 代码段:存储程序的指令代码。
- 数据段:存储全局变量和静态数据。
- 堆:用于动态内存分配,通常通过
malloc
或new
分配。 - 栈:存储函数调用信息、局部变量等。
这些不同的段在虚拟地址空间中是线性排列的,且每个段都有一个特定的起始地址和大小。虚拟地址空间通过页表映射到物理内存中的离散位置,程序在运行时依然认为自己是在操作一块连续的内存空间。
4. 虚拟地址空间和物理内存的映射
编译器生成的线性地址(或虚拟地址)在程序运行时通过页表机制映射到物理内存。这个映射过程是完全透明的,程序并不关心自己的线性地址在物理内存中的实际位置。操作系统和硬件通过以下机制管理这个过程:
- 页表:操作系统为每个进程维护一个页表,记录虚拟地址到物理地址的映射。
- 内存管理单元(MMU):硬件组件 MMU 负责在程序执行时,将每次的虚拟地址访问通过页表转换为物理地址,从而访问实际的物理内存。
- 分页机制:虚拟地址空间被分割成固定大小的页(通常是 4KB),每个虚拟页可以映射到不同的物理页。因此,虚拟地址空间可以是线性连续的,而物理地址空间则可以是离散的。
5. 虚拟地址和线性地址的互换性
从程序的角度来看,编译器生成的线性地址空间和虚拟地址空间没有区别。程序始终以为自己运行在一个连续的、独占的内存区域中,而虚拟内存技术在后台通过页表和地址转换来管理这种假象。因此,在有虚拟内存支持的环境下,编译器生成的线性地址实际上就是虚拟地址。
总结
在有虚拟内存技术的环境下,编译器生成的线性地址空间实际上就是程序的虚拟地址空间,只是在不同的语境下有不同的叫法。编译器生成的线性地址在运行时通过操作系统和硬件的页表机制映射到实际的物理内存,而这种映射是对程序透明的。程序不需要知道其虚拟地址对应的物理地址位置,依然可以按照逻辑上连续的地址空间正常执行。
附图
CPU在不打开分页机制的情况下,是按照默认的分段方式进行的,段基址和段内偏移地址经过段部件处理后所输出的线性地址,CPU就认为是物理地址。如果打开了分页机制,段部件输出的线性地址就不再等同于物理地址了,我们称之为虚拟地址,它是逻辑上的,是假的,不应该被送上地址总线(因为地址只是个数字,任何数字都可以当作地址,这里说的“不应该”是指应该人为保证送上地址总线上的数字是正确的地址)。CPU必须要拿到物理地址才行,此虚拟地址对应的物理地址需要在页表中查找,这项查找工作是由页部件自动完成的。
特别注意:经过段部件处理后,保护模式的寻址空间是4GB,注意啦,这个寻址空间是指线性地址空间,它在逻辑上是连续的