詳解.NET IL代碼


一、前言

IL是什么?

 Intermediate Language (IL)微軟中間語言

C#代碼編譯過程?

C#源代碼通過LC轉為IL代碼,IL主要包含一些元數據和中間語言指令;

JIT編譯器把IL代碼轉為機器識別的機器代碼。如下圖

語言編譯器:無論是VB code還是C# code都會被Language Compiler轉換為MSIL

MSIL的作用:MSIL包含一些元數據和中間語言指令

JIT編譯器的作用:根據系統環境將MSIL中間語言指令轉換為機器碼

為什么ASP.NET網站第一次運行時會較慢,而后面的執行速度則會相對快很多?

當你第一次運行.NET開發的站點時,CLR會將MSIL通過JIT進行編譯,最終轉換為執行速度非常快的Native Code。這可以解釋。

為什么要了解IL代碼?

如果想學好.NET,IL是必須的基礎,IL代碼是.NET運行的基礎,當我們對運行結果有異議的時候,可以通過IL代碼透過表面看本質;

IL也是更好理解、認識CLR的基礎;

大量的實例分析是以IL為基礎的,所以了解IL,是讀懂他人代碼的必備基礎,同時自己也可以獲得潛移默化的提高;

二、如何把ILDasm導入到VS中

想要看IL代碼需要使用ILDasm工具,工具一般在電腦的

C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\bin\ildasm.exe

也可以下載ILSpy:http://ilspy.net/

把ILDasm導入到VS工具中,使用方便,具體如下:工具 - > 外部工具 

  

導入之后,vs工具里面就有ILDasm工具了。以后想看IL代碼方便多了。

IL代碼通過ILDasm反編譯后(左圖),ILDasm圖標意義(右圖)

  

三、分析IL代碼

在分析IL代碼之前,要先理解幾個概念:

圖片來源:https://msdn.microsoft.com/zh-tw/library/dd229210.aspx

Managed Heap(托管堆):這就是NET中的托管堆,用來存放引用類型,它是由GC(垃圾回收器自動進行回收)管理;

Call Stack(調用堆棧):調用堆棧:調用堆棧是一個方法列表,按調用順序保存所有在運行期被調用的方法。

Evaluation Stack(計算堆棧):每個線程都有自己的線程棧,IL 里面的任何計算,都發生在 Evaluation Stack 上,其實就是一個 Stack 結構。可以 Push,也可以 Pop。

可以對照IL指令:指令列表,一步一步來分析IL代碼

1、用C#寫一個簡單控制台應用程序

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:從當前方法返回,並將返回值(如果存在)從調用方的計算堆棧推送到被調用方的計算堆棧上。

call:調用由傳遞的方法說明符指示的方法。

box:將值類轉換為對象引用,就是裝箱,同理可以知道拆箱unbox

 

ldc.i4.X:把int32的值推送到計算堆棧

stloc.X:把計算堆棧頂部的值放到調用堆棧索引為X處

ldloc.X:把調用堆棧X處的值復制到計算堆棧

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的值)放到調用堆棧索引0處
  IL_0003:  ldc.i4.2  //把j的值放到計算堆棧上
  IL_0004:  stloc.1   //把計算堆棧頂部的值(j的值)放到調用堆棧索引1處
  IL_0005:  ldc.i4.3  //把k的值放到計算堆棧上
  IL_0006:  stloc.2   //把計算堆棧頂部的值(k的值)放到調用堆棧索引2處

  IL_0007:  ldloc.0   //把調用堆棧索引為0處的值復制到計算堆棧 
  IL_0008:  ldloc.1   //把調用堆棧索引為1處的值復制到計算堆棧
  IL_0009:  add       //相加
  IL_000a:  ldloc.2   //把調用堆棧索引為2處的值復制到計算堆棧
  IL_000b:  add       //相加
  IL_000c:  stloc.3   //把計算堆棧頂部的值(add的值)放到調用堆棧索引3處
  IL_000d:  ldstr      "i+j+k="  //推送對元數據中存儲的字符串的新對象引用。
  IL_0012:  ldloc.3   //把調用堆棧索引為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)       //調用WriteLine
  IL_0022:  nop       //無操作
  IL_0023:  call       valuetype [mscorlib]System.ConsoleKeyInfo [mscorlib]System.Console::ReadKey()  //調用ConsoleKey
  IL_0028:  pop      //無操作
  IL_0029:  ret      //return
} // end of method Program::Main

四、最后

IL是跟我高級架構經理的分享和博客園相關的博客學習總結的,最后留2個題目,也是我的高級架構經理分享中提到的兩個好玩的問題,也能看出對IL的掌握的程度

 答案后續公布。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM