| 
 來源:Joye.Net
 鏈接:http://www.cnblogs.com/yinrq/p/5486103.html
 
一、前言
 IL是什么? 
  Intermediate Language (IL)微軟中間語言 
 C#代碼編譯過程? 
 C#源代碼通過LC轉(zhuǎn)為IL代碼,IL主要包含一些元數(shù)據(jù)和中間語言指令; 
 JIT編譯器把IL代碼轉(zhuǎn)為機器識別的機器代碼。如下圖 
 
 
 語言編譯器:無論是VB code還是C# code都會被Language Compiler轉(zhuǎn)換為MSIL 
 MSIL的作用:MSIL包含一些元數(shù)據(jù)和中間語言指令 
 JIT編譯器的作用:根據(jù)系統(tǒng)環(huán)境將MSIL中間語言指令轉(zhuǎn)換為機器碼 
 為什么ASP.NET網(wǎng)站第一次運行時會較慢,而后面的執(zhí)行速度則會相對快很多? 
 當(dāng)你第一次運行.NET開發(fā)的站點時,CLR會將MSIL通過JIT進行編譯,最終轉(zhuǎn)換為執(zhí)行速度非常快的Native Code。這可以解釋。 
 為什么要了解IL代碼? 
 如果想學(xué)好.NET,IL是必須的基礎(chǔ),IL代碼是.NET運行的基礎(chǔ),當(dāng)我們對運行結(jié)果有異議的時候,可以通過IL代碼透過表面看本質(zhì); 
 IL也是更好理解、認識CLR的基礎(chǔ); 
 大量的實例分析是以IL為基礎(chǔ)的,所以了解IL,是讀懂他人代碼的必備基礎(chǔ),同時自己也可以獲得潛移默化的提高; 
 二、如何把ILDasm導(dǎo)入到VS中
 想要看IL代碼需要使用ILDasm工具,工具一般在電腦的 
 C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\bin\ildasm.exe 
 也可以下載ILSpy:http:/// 
 把ILDasm導(dǎo)入到VS工具中,使用方便,具體如下:工具 - > 外部工具  
   
 
 導(dǎo)入之后,vs工具里面就有ILDasm工具了。以后想看IL代碼方便多了。 
 IL代碼通過ILDasm反編譯后(左圖),ILDasm圖標意義(右圖) 
  
 
 
 
三、分析IL代碼
 在分析IL代碼之前,要先理解幾個概念: 
 
 
 圖片來源:https://msdn.microsoft.com/zh-tw/library/dd229210.aspx Managed Heap(托管堆):這就是NET中的托管堆,用來存放引用類型,它是由GC(垃圾回收器自動進行回收)管理; 
 Call Stack(調(diào)用堆棧):調(diào)用堆棧:調(diào)用堆棧是一個方法列表,按調(diào)用順序保存所有在運行期被調(diào)用的方法。 
 Evaluation Stack(計算堆棧):每個線程都有自己的線程棧,IL 里面的任何計算,都發(fā)生在 Evaluation Stack 上,其實就是一個 Stack 結(jié)構(gòu)??梢?Push,也可以 Pop。 
 可以對照IL指令:指令列表,一步一步來分析IL代碼 
 1、用C#寫一個簡單控制臺應(yīng)用程序 
 using System; 
 namespace ILDemo {     class Program     {         static void Main(string[] args)         {             int i = 1;             int j = 2;             int k = 3;             int answer = i + j + k;             Console.WriteLine('i+j+k=' + answer);             Console.ReadKey();         }     } }
 
 2、 用ILDasm打開bin下的.exe文件查看代碼,具體IL代碼如下: 
 .method private hidebysig static void  Main(string[] args) cil managed {   .entrypoint    // 代碼大小       42 (0x2a)   .maxstack  2   .locals init ([0] int32 i,            [1] int32 j,            [2] int32 k,            [3] int32 answer)   IL_0000:  nop   IL_0001:  ldc.i4.1   IL_0002:  stloc.0   IL_0003:  ldc.i4.2   IL_0004:  stloc.1   IL_0005:  ldc.i4.3   IL_0006:  stloc.2   IL_0007:  ldloc.0   IL_0008:  ldloc.1   IL_0009:  add   IL_000a:  ldloc.2   IL_000b:  add   IL_000c:  stloc.3   IL_000d:  ldstr      'i+j+k='   IL_0012:  ldloc.3   IL_0013:  box        [mscorlib]System.Int32   IL_0018:  call       string [mscorlib]System.String::Concat(object,                                                               object)   IL_001d:  call       void [mscorlib]System.Console::WriteLine(string)   IL_0022:  nop   IL_0023:  call       valuetype [mscorlib]System.ConsoleKeyInfo [mscorlib]System.Console::ReadKey()   IL_0028:  pop   IL_0029:  ret } // end of method Program::Main
 
 3、會用到的IL指令: 
 nop:無操作 
 ret:從當(dāng)前方法返回,并將返回值(如果存在)從調(diào)用方的計算堆棧推送到被調(diào)用方的計算堆棧上。
 
 call:調(diào)用由傳遞的方法說明符指示的方法。 
 box:將值類轉(zhuǎn)換為對象引用,就是裝箱,同理可以知道拆箱unbox   ldc.i4.X:把int32的值推送到計算堆棧 
 stloc.X:把計算堆棧頂部的值放到調(diào)用堆棧索引為X處 
 ldloc.X:把調(diào)用堆棧X處的值復(fù)制到計算堆棧 
 4、理解注釋后的代碼 
 .method private hidebysig static void  Main(string[] args) cil managed {   .entrypoint  //程序入口   // 代碼大小       42 (0x2a)   .maxstack  2    // 計算出計算堆棧的能存幾個值 
   .locals init ([0] int32 i,            [1] int32 j,            [2] int32 k,            [3] int32 answer) //定義int32類型的i,j,k,answer 
   IL_0000:  nop   //無操作 
   IL_0001:  ldc.i4.1  //把i的值放到計算堆棧上   IL_0002:  stloc.0   //把計算堆棧頂部的值(i的值)放到調(diào)用堆棧索引0處   IL_0003:  ldc.i4.2  //把j的值放到計算堆棧上   IL_0004:  stloc.1   //把計算堆棧頂部的值(j的值)放到調(diào)用堆棧索引1處   IL_0005:  ldc.i4.3  //把k的值放到計算堆棧上   IL_0006:  stloc.2   //把計算堆棧頂部的值(k的值)放到調(diào)用堆棧索引2處 
   IL_0007:  ldloc.0   //把調(diào)用堆棧索引為0處的值復(fù)制到計算堆棧    IL_0008:  ldloc.1   //把調(diào)用堆棧索引為1處的值復(fù)制到計算堆棧   IL_0009:  add       //相加   IL_000a:  ldloc.2   //把調(diào)用堆棧索引為2處的值復(fù)制到計算堆棧   IL_000b:  add       //相加   IL_000c:  stloc.3   //把計算堆棧頂部的值(add的值)放到調(diào)用堆棧索引3處   IL_000d:  ldstr      'i+j+k='  //推送對元數(shù)據(jù)中存儲的字符串的新對象引用。   IL_0012:  ldloc.3   //把調(diào)用堆棧索引為3處的值復(fù)制到計算堆棧 
   IL_0013:  box        [mscorlib]System.Int32     //裝箱   IL_0018:  call       string [mscorlib]System.String::Concat(object,object)   //調(diào)用內(nèi)部方法   IL_001d:  call       void [mscorlib]System.Console::WriteLine(string)       //調(diào)用WriteLine   IL_0022:  nop       //無操作   IL_0023:  call       valuetype [mscorlib]System.ConsoleKeyInfo [mscorlib]System.Console::ReadKey()  //調(diào)用ConsoleKey   IL_0028:  pop      //無操作   IL_0029:  ret      //return } // end of method Program::Main
 
 |