1.4执行程序集代码
托管模块中包含着元数据和
IL
代码。
IL
是由微软在咨询了一些商业和学术上的语言编译器作者之后开发的一种独立于
CPU
的机器语言。
IL
要比大多数
CPU
机器语言高级得多,它可以理解对象类型,并且拥有很多高级的指令,这些指令可以创建和初始化对象,调用对像上的虚方法以直接操作数组元素。它甚至还有抛出和捕获异常的指令。我们可以把
IL
视
作一种面向对像的机器语言。
通常情况上,开发人员会使用一门高级语言,比如:
C#
或
Visual Basic)
。这些语言的编译器産的将是
IL
代码。当然,我们也可以直接以汇编语言的方法写
IL
程序。微软也提供了一个
IL
汇编器:
ILAsm.exe,
另外还有一个反汇编器:
ILDdsm.exe
。
C#
或者
Visual Basic
等高级语言提供的都只是
CLR
全部功能的一个子集。
IL
汇编语言允许开发人员获取
CLR
所有的功能。
总结
IL
的特点如下:
1
、面向对像特性,与其他汇编不同。
2
、
IL
可以获取
CLR
所有的功能
3
、
IL
并不束缚于任何特定的
CPU
平台,也就是说他也可以夸平台。
.net
程序执行过程如下:
1
一个方法执行之前,
CLR
首先检测
Main
中代码引用的所有类型,
CLR
会分配一个内部的数据结构,该数据结构用于管理对所引用类型的访问。
2
、当该数据结构被初始化时,
CLR
将把每一个条目设置
为
CLR
内部的一个没有正式记录的函数,我们暂且称该函数为
JITCompiler
。
3
、当
Main
方法第一次调用引用的类型的方法成员时,
JITCompiler
函数将被调用,该函数负责将一个方法的
IL
代码编译成本地
CPU
指令。
1、
JITCompiler
将前面第
2
步的数据结构中的要调用的真实方法的地址替换成包含刚刚编译好的
CPU
指令的内存块地址。
2、
JITCompiler
跳转到该内存块中的代码上,开始执行。
注意:一个类型的所有方法只会编译一次,当这个类型的方法又被调用时,将会使用之前已经编译过的代码,这样只有在首次调用时,才会产生性能损失。
也就是说托管代码跟非托管代码相比,性能上的损失是非常小的,近乎微不足道。
托管代码在性能上的优点:
1、
在新型的如奔
4CPU
上,
JIT
编译器能产生利用新型
CPU
提供的特殊指令的本地代码。而非托管应用程序通常被编译为向具有最小通用功能集合的
CPU
平台,一般会避免使用新型
CPU
提供的特殊指令。而这些特殊指令往往会在较新的
Cpu
上为应用程序带来很高的性能提升中。
2、
JIT
编译器能检测到正在运行的机器上某些总是返回错误的布尔测试。例如:
If(numberOfCPUs>1)
{
}
如果宿主机器只有一个
CPU
,那么对于该段代码,
JIT
编译器将不会产生任何
CPU
指令。针对宿主机器的本地代码鶁会得到更好的调整:代码量将变得更小,执行速度也会更快。
当然,我们可以利用
Ngen.exe
工具,将
IL
代码转化为本地代码,并生成一个文件,这样执行程序时,
CLR
将自动检查是否有个预编译的版本存在,如果存在,
CLR
将加载预编译的代码,不需要额外的运行时编译。
1.4.1 IL与代码验证
1、
IL
是一种基于堆栈的语言
2、
IL
没有提供操作寄
存器的指令,开发人员可以很容易地产生
IL
代码。
3、
IL
需要的指令也比较少。
4、
IL
指令是无类型的。
5、
IL
对
CPU
实现了抽象。
IL
的最大优点是:提高了应用程序的健壮性,当
IL
代码被编译为本地
Cpu
指令时,
CLR
将执行一个称作验证的过程。
验证过程检查高级
IL
代码,确保它做的每件事情都是“安全”的。以下是检验的一些条目:
1、
不能从未初始化的内存中读取数据。
2、
每个方法都必须传入正确的参数个数,且各个参数的类型要正确匹配。
3、
每个方法的返回值都必须被正确地使用。
4、
每个方法都必须有一个返回语句
。。。。
如果验证不通过,将有一个
System.Security.VerificationException
异常被抛出,阻止方法继续执行。
验证的优点:
通过验证的代码,我们可以确保它们不会访问它们不应该访问的的内存,因此也就不会干扰另一个应用程序的代码。这意味着我们可以在一个单独的
windows
虚拟地址空间内运行多个托管应用程序。