NET框架程序设计读书笔记(3)--执行程序集代码
发表时间:2023-08-01 来源:明辉站整理相关软件相关文章人气:
[摘要]1.4执行程序集代码托管模块中包含着元数据和IL代码。IL是由微软在咨询了一些商业和学术上的语言编译器作者之后开发的一种独立于CPU的机器语言。IL要比大多数CPU机器语言高级得多,它可以理解对象类...
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虚拟地址空间内运行多个托管