程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> C#入門知識 >> 讀懂IL代碼(二),讀懂il代碼

讀懂IL代碼(二),讀懂il代碼

編輯:C#入門知識

讀懂IL代碼(二),讀懂il代碼


上一篇提到了最基本的IL代碼,應該是比較通俗易懂的,所以有了上一篇的基礎之後,這篇便要深入一點點的來講述了。

首先我必須再來說一些重要的概念:

Evaluation Stack(評估棧):這是由.NET CLR在執行時候自動管理的記憶體,每一個線程都有自己的評估棧,也就是說,它是用來存儲臨時變量的線程棧(應該可以這麼理解)。值類型存儲數據,引用類型存儲地址。

Call Stack(調用棧):這也是由.NET CLR在執行時候自動管理的記憶體,每一個線程都有自己的調用棧,每一次調用method,就會產生一個棧幀(stack frame),當方法結束的時候,此棧幀就會被丟棄。

大家一定疑問怎麼都是棧呀,堆到哪裡去了嘞,大家別急,下面說:

Managed Heap:這是動態配置的記憶體,由Garbage Collector(GC)執行時自動管理,整個程序共用一個。我把這個理解為托管堆,用來存儲引用類型的值。

這一篇主要是以引用類型為主來講述IL代碼。

大家都知道把值類型變成引用類型是采用裝箱的操作,所以這裡也先說一下裝箱的過程:

(1)內存分配,在Managed Heap(托管堆)中分配一個內存空間;

(2)將值類型的字段拷貝到分配的內存中;

(3)將托管堆中的對象地址返回給新的對象,Over。

 

以上是一些基本知識點,現在主要來講解IL代碼:

正規代碼如下:

我用Reflector進行查看IL代碼:

 

上圖就是IL代碼了,經過上一篇的介紹,我覺得這裡大家應該也看得懂吧,下面我就來解釋這段IL代碼吧。

.method private hidebysig static void Main(string[] args)cilmanaged
{
    .entrypoint //入口
    .maxstack 2 //評估棧可容納數據項的最大個數。
    .locals init ( 
        [0] string str,
        [1] int32 num) //定義並初始化參數,並存入局部變量表(Call Stack)中。
    L_0000: nop //No Operation
    L_0001: ldstr "Helius" //將字符串“Helius”壓入評估棧中。
    L_0006: stloc.0  //將字符串從評估棧中彈出,賦值給局部變量表的第0個變量。
    L_0007: ldc.i4.s 0x1b //解析:int類型的數值大小不一樣,IL代碼也是不一樣的。比如int i=-1;IL代碼為ldc.i4.M1;當i的值大於等於9的時候,IL代碼就為ldc.i4.s(i的十六進制表示形式),當i的值小於等於-2時,IL代碼表示為ldc.i4.s(i)。
    L_0009: stloc.1 //將值從評估棧中彈出,賦值給局部變量表的第1個變量。
    L_000a: ldloca.s num //取出局部變量表中num的值“27”並壓入評估棧中。
    L_000c: call instance string [mscorlib]System.Int32::ToString() //從評估棧中取出數值“27”,調用ToString方法轉成string類型並將引用存入評估棧中。
    L_0011: ldloc.0 //取出局部變量表中的第0個位置元素值“Helius”,並壓入評估棧,(此時評估棧中有兩個值,字符串“Helius”和“27”的引用地址)。
    L_0012: call string [mscorlib]System.String::Concat(string, string) //調用String類的Concat方法把字符串拼接並存入托管堆中,把引用地址返回給評估棧。
    L_0017: call void [mscorlib]System.Console::WriteLine(string) //調用輸出方法,調用輸出方法後評估棧中的值(指向托管堆中字符的地址)會被回收。
    L_001c: nop  
------------------------------------------分割線--------------------------------------------------------------------------------------------------- L_001d: ldloc.1 //取局部變量表中的第1個位置參數num值,存入評估棧中。 L_001e: box int32 //把num值27裝箱,並返回托管堆中的地址存入評估棧中。 L_0023: ldloc.0 //去局部變量表中的第0個參數,並壓入評估棧中。 L_0024: call string [mscorlib]System.String::Concat(object, object)//彈出評估棧中兩個值,並調用String的Concat方法把字符拼接,存入托管堆中,並返回引用地址到評估棧中。 L_0029: call void [mscorlib]System.Console::WriteLine(string) //調用輸出方法。 L_002e: nop L_002f: call valuetype [mscorlib]System.ConsoleKeyInfo [mscorlib]System.Console::ReadKey()//調用ReadKey方法 L_0034: pop //把評估棧的內容清空 L_0035: ret //return 標記返回 }

以圖來解釋上面的例子可能更明白一點(程序員學會畫圖很重要,我記得去面試的時候,面試官還叫我畫項目的架構圖):
圖1



圖2




圖3

 從以上的圖中可以明顯看出調用方法與裝箱的流程。引用類型都是存放在托管堆裡面的,而棧只存放引用類型的地址,這點是要特別注意的。

下一篇我會寫方法,委托和類的IL代碼解析。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved