程序是保存在硬盘中的,要载入内存才能运行,CPU也被设计为只能从内存中读取数据和指令。
对于CPU来说,内存仅仅是一个存放指令和数据的地方,并不能在内存中完成计算功能,
如:计算a= b+ c, 必须将a, b, c都读取到CPU内部才能进行加法运算。
CPU结构如下:
其中运算单元:是CPU的大脑,负责加减乘除,比较,位移等运算。
寄存器:CPU内部非常小,非常快速的存储不见,容量很有限,对于64 位的CPU,每个寄存器一般能存储64 位(8 个字节)的数据。一般:现代CPU内置了几十个或几百个寄存器,嵌入式系统功能单一,寄存器数量较少。(我们经常说的CPU多少位,指的就是寄存器的位数)
用途:完成数学运算,控制循环次数,程序的执行流程等。
缓存:虽然内存读取速度已经很快了,但和CPU比,相差甚远,如果每次偶读从内存读取数据,会严重拖慢CPU的运行速度。缓存容量是有限的,对于不是很频繁使用的数据,会绕过缓存,直接到内存中读取。
CPU指令:要让CPU工作,必须借助特定的指令,例:add用于加法运算,sub除法等。
假设有下面的C语言代码:
int a = 0X14 , b = 0XAE , c;
c = a + b;
在VS2010 Debug模式下生成的CPU指令为:
mov ptr[ a] , 0X14
mov ptr[ b] , 0XAE
mov eax, ptr[ a]
add eax, ptr[ b]
mov ptr[ c] , eax
虚拟内存:
代码:
# include <stdio.h>
# include <stdlib.h>
int a = 1 , b = 255 ;
int main ( ) {
int * pa = & a;
printf ( "pa = %#X, &b = %#X\n" , pa, & b) ;
system ( "pause" ) ;
return 0 ;
}
结果:
pa = 0X402000 , & b = 0X402004
代码a,b是全局变量,他们的内存地址在链接时就已经决定了,再也不能改变,所以程序运行结果都是一样的。
问题:若物理内存中的这两个地址被其他程序占用了,程序是否无法运行?
幸运的是,这些内存地址都是假的,不是真实的物理内存地址,而是虚拟地址。虚拟地址通过CPU的转换才能对应到物理地址,且每次程序运行,操作系统都会重新安排虚拟地址和物理地址的对应关系,
哪一段物理内存空闲就使用哪一段,如下图:
虚拟地址:程序给出的地址,通过某种映射的方法,将虚拟地址转换为实际的物理地址。
只有我们可以妥善的控制这个映射过程,就可保证每次运行时都使用相同的地址。
例:上面代码中变量 a 的地址是 0X402000 ,第一次运行时它对应的物理内存地址可能是 0X12ED90AA ,第二次运行时可能又对应 0XED90 ,而我们的程序不需要关心这些,这些繁杂
的内存管理工作交给操作系统处理即可。
除了编程时可以使用固定的内存地址,给程序员带了方便,使用虚拟地址还能使得不同程序
的地址空间相互隔离,提供内存使用率。
1. 使不同程序的地址空间相互隔离:
使用虚拟地址后,程序A和B虽然都可访问同一个地址,但他们对应的物理地址是不同的,无论如何操作,都不会修改对方的内存。
2. 提高内存使用效率
使用虚拟地址后,操作系统会更多地介入到内存管理工作中,这使得控制内存权限成为可能。