进入山东省住房和城乡建设厅网站,在哪里做马可波罗网站,in word in the wordpress,汕头做网站一、IL与汇编语言IL是微软.NET平台上衍生出的一门中间语言#xff0c;.NET平台上的各种高级语言(如C##xff0c;VB#xff0c;F#)的编译器会将各自的代码转化为IL。#xff0c;其中包含了.NET平台上的各种元素#xff0c;如“范型”#xff0c;“类”、、“接口”、“模…一、IL与汇编语言IL是微软.NET平台上衍生出的一门中间语言.NET平台上的各种高级语言(如C#VBF#)的编译器会将各自的代码转化为IL。其中包含了.NET平台上的各种元素如“范型”“类”、、“接口”、“模块”、“属性”等等。值得注意的是各种高级语言本身可能根本没有这些“概念”在里头如IronScheme是一个在.NET平台上的Scheme语言实现其中根本没有前面提到的这些IL——亦或说是.NET平台上的名词。IL本身并不知道自己是由哪种高级语言转化而来的哪种语言中有哪些特性IL也根本不会关心。各种语言的编译器将高级语言 IL。汇编是让CPU直接使用的“语言”请注意“直接”二字一条汇编指令便是让CPU作一件事情(如寄存器的复制从内存中读取数据等等)毫无二义。不同族CPU拥有不同的指令集但是它们都有一样的特征指令的数量相对较少每个指令功能都简单之至。由于CPU只认识汇编代码(机器码和汇编其实也是一一对应的您可以这样理解汇编是机器码的文字表现形式提供了一些方便人们记忆的“助记符”)因此就算是IL也需要再次进行转化才能被CPU执行。这次转化便由“JIT Compiler”(即时编译器)完成。CLR加载了IL之后当每个方法——请注意这是IL中的概念——第一次被执行时就会使用JIT将IL代码进行编译为机器码。与IL不同的是CLRJIT都是真正了解CPU的对于同样的ILJIT会把它为不同的CPU架构(如x86/IA64等等)生成不同的机器码。这也是Java/.NET中“Compile OnceRun Everywhere”这一口号的技术基础它们为不同的CPU架构提供了不同的“IL转化器”仅此而已。与高级语言到IL的转化类似CPU也完全不知道自己在执行的指令是从哪里来的可能是JIT从IL转化而来可能是JVM从Java Bytecode转化而来也有可能是C语言编译得来也有可能是由MIT/GNU Scheme解释而来。这就是.NET平台上的高级语言在机器上运行的第二次转化IL 汇编(机器码)。因此IL和汇编的区别是显著的。IL拥有各种高级特性它知道什么是范型什么是类和方法(以及它们的“名称”)什么是继承什么是字符串布尔值什么是User对象。而CPU只知道寄存器地址内存01010101。与汇编相比IL简直太高级了几乎完全是一个高级语言比C语言还要高级。因此您会看到.NET Reflector几乎可以把IL代码“一五一十”地反编译为可读性良好的C#代码包括类属性方法等等而从汇编只能勉勉强强地反编译为C语言——而且其中的“方法名”等信息已经完全不可恢复了更别说“模块”等高级抽象的内容。您想要把汇编反编译成C#代码相信在将来这是可行的不过现在这还是天方夜谭。二、IL并不是万能的CLR还有很多内容IL都无法看到示例一探究泛型在某些情况下的性能问题namespace TestConsole{public class MyArrayList{public MyArrayList(int length){this.m_items new object[length];}private object[] m_items;public object this[int index]{[MethodImpl(MethodImplOptions.NoInlining)]get{return this.m_items[index];}[MethodImpl(MethodImplOptions.NoInlining)]set{this.m_items[index] value;}}}public class MyList{public MyList(int length){this.m_items new T[length];}private T[] m_items;public T this[int index]{[MethodImpl(MethodImplOptions.NoInlining)]get{return this.m_items[index];}[MethodImpl(MethodImplOptions.NoInlining)]set{this.m_items[index] value;}}}class Program{static void Main(string[] args){MyArrayList arrayList new MyArrayList(1);arrayList[0] arrayList[0] ?? new object();MyList list new MyList(1);list[0] list[0] ?? new object();Console.WriteLine(Here comes the testing code.);var a arrayList[0];var b list[0];Console.ReadLine();}}}示例目的是证明“.NET中就算在使用Object作为泛型类型的时候也不会比直接使用Object类型性能差”。类MyList泛型容器类MyArrayList直接使用Object类型的容器。在Main方法中将对MyList和MyArrayList的下标索引进行访问。至此便出现了一些疑问为泛型容器使用Object类型是否比直接使用Object类型性能要差看MyArrayList.get_Item和MyList.get_Item两个方法的IL代码get操作// MyArrayList的get_Item方法.method public hidebysig specialname instance object get_Item(int32 index) cil managed noinlining{.maxstack 8L_0000: ldarg.0L_0001: ldfld object[] TestConsole.MyArrayList::m_itemsL_0006: ldarg.1L_0007: ldelem.refL_0008: ret}// MyList的get_Item方法.method public hidebysig specialname instance !T get_Item(int32 index) cil managed noinlining{.maxstack 8L_0000: ldarg.0L_0001: ldfld !0[] TestConsole.MyList1::m_itemsL_0006: ldarg.1L_0007: ldelem.any !TL_000c: ret}这两个方法的区别只在于红色的两句。我们“默认”ldfld指令的功能在两段代码中产生的效果完全相同(毕竟是相同的指令嘛)但是您觉得ldelem.ref指令和ldelem.any两条指令的效果如何它们是一样的吗我们通过查阅一些资料可以了解到说ldelem.any的作用是加载一个泛型向量或数组中的元素。不过它的性能如何您能得出结果说它就和ldelem.ref指令一样吗除非您了解到JIT对待这两个指令的具体方式否则您是无法得出其中性能高低的。因为IL还是过于高级您看到了一条IL指令您可以知道它的作用但是您还是不知道它最终造成了何种结果。您还是无法证明“Object泛型集合的性能不会低于直接存放Object的非泛型集合”。因此比较MyArrayList.get_Item方法和MyList.get_Item方法的汇编代码最后得出结果是“毫无二致”。由于汇编代码和机器代码一一对应因此观察汇编代码就可以完全了解CPU是如何执行这两个方法的。汇编代码一模一样就意味着CPU对待这两个方法的方式一模一样它们的性能怎么会有不同呢结论.NET的Object泛型容器的性能不会低于直接使用Object的容器因为CLR在处理Object泛型的时候会生成与直接使用Object类型时一模一样的类型因此性能是不会降低的。但是您是通过学习IL可以了解这些吗显然不是如果您只是学习了IL最终还是要“听别人说”才能知道这些而即使您不学IL在“听别人说”了之后您也了解了这些——同时也不会因为不了解IL而变得“易忘”等等。同样道理IL的call指令和callvirt指令的区别是什么呢“别人会告诉你”call指令直接就去调用了那个方法而callvirt还需要去虚方法表里去“寻找”那个真正的方法“别人可能还会告诉你”查找虚方法是靠方法表地址加偏移量《Essential .NET》还会将方法表的实现结构告诉给你而这些都是IL不会告诉您的。您就算了解再多IL也不如“别人告诉你”的这些来得重要。您要了解“别人告诉你”的东西也不需要了解多少IL。示例二只有经过调用的方法才能获得其汇编代码吗许多资料都告诉我们在一个方法被第一次调用之前它是不会被JIT的。也就是说直到第一次调用时它才会被转化为机器码。不过这个真是这样吗我们还是准备一段简单的C#代码