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