计算机有两种存储器:外存和内存。
内存:通常容量较小,存取数据的速度非常快,但一旦停电后,其中的信息会完全丢失。
外存:有许多种,如光盘、U盘和硬盘等,其特点是容量大,存取速度较慢,但停电之后信息仍然存在。
人类写的程序,经过编译器转为机器指令后,一般以文件的方式保存在外存储器中,当CPU执行程序时,要先把外存储器中的指令读入到内存中。内存被分成很多块,每块都有一个惟一的地址,指令就存放在以某个特定的地址(称为入口地址)开始的内存区域中。CPU从入口地址处取出第一条机器指令,开始执行,然后再取第二条,依次类推。
非托管代码不仅不能在不同种类的计算机上执行,而且,在不同的操作系统下也不能执行。比如一个Windows应用程序就无法在Linux下运行,反之亦然。
显然,如果需要在不同的计算机和操作系统上实现同一功能,就不得不为每种操作系统和计算机各写一种代码。这显然是一种重复且低效的劳动。
程序能不能只写一次,处处运行?
程序最终还是要靠CPU执行,所以.NET的MSIL仍然需要最终被翻译成CPU能执行的机器指令,这部分功能由一个运行在特定操作系统之上的软件系统来完成,这个软件系统称为VM(Virtual Machine,虚拟机)。
只需要为每种操作系统和特定的硬件平台提供一个虚拟机,就可以让同样一个程序不加修改地在不同的操作系统和硬件结构的计算机上运行。
这种运行在虚拟机之上的代码称为托管代码
.NET Framework,其实就是一个运行在操作系统Windows之上的软件虚拟机。使用VS NET开发出来的程序经过编译之后,生成的可执行程序实际上包含的只是MSIL指令代码,这是一种托管代码,只能运行在.NET虚拟机之上。所以,如果某台计算机上没有安装.NET Framework,就意味着图1-50中的“虚拟机”一层不存在,.NET应用程序就无法执行。对于非Windows的操作系统,只要上面有.NET虚拟机,就可以运行.NET程序,不需要重新修改源程序并重新编译。
把一个程序从硬盘上装入内存执行是一个复杂的过程,这个功能由操作系统实现,开发具体应用程序的软件工程师不需要自己动手去写这部分代码.程序的运行必须依赖于操作系统(如Windows和Linux),而且编译器生成的程序文件包含的是特定CPU的机器指令。由于不同CPU的机器指令不同,所以,生成的程序不能不加修改地在具有不同种类CPU的计算机上运行。
以这种方式生成的机器指令代码称为非托管代码