在瞭解CLR運行以前讓咱們先簡單瞭解一下IL服務器
除了編譯器編譯的IL代碼,IL也是一種彙編語言,也就是說咱們能夠直接編寫IL代碼,固然也有對應的IL編譯器,值得一提的是對於面向CLR的其餘語言,
CLR只開放了一部分功能,而IL能夠訪問CLR的所有功能。數據結構
前面一章咱們介紹了CLR的全部初始工做,最後在調用Main入口方法的時候,CLR須要將程序集中的IL代碼轉爲CPU指令,也就是CLR中JIT(just-in-time)
編譯器的職責,CLR會即時編譯IL代碼函數
即時編譯:在運行的時候纔會進行編譯(相似懶加載)
當CLR運行並調用方法時作了以下幾件事情
一、檢測出全部方法中全部被引用的類型,並建立一個內部數據結構進行管理,每一個類型的方法都會記錄指向名爲JITComplier函數的地址,
二、在方法被調用的時候,函數會在與元數據中查找被調用的方法對應的IL代碼,對其驗證並將代碼編譯成CPU指令
三、將CPU指令存貯到動態分配的內存中
四、回到內部數據結構中,修改對應方法記錄的地址,指向剛纔編譯好的CPU指令的地址
五、最後函數會回到內存當中去運行CPU指令工具
至此一個方法調用的所有流程就走完了,若是不終止程序(終止會將編譯好的cpu指令丟棄),那麼CLR在第二次調用方法時,直接在數據
結構中找到對應的內存運行CPU指令,省去了上面的二、三、4步驟性能
CLR的JIT編譯器以及C#編譯器對本機代碼的優化
C#編譯器 :
/optimize 關閉 --> 編譯出的IL代碼會包含許多NOP指令(no-operation 空操做)和跳轉執行,vs就是利用的這些指令提供了調試的功能
/optimize 開啓 --> 優化後的代碼會更小,程序集也會相應變小,更方便閱讀IL代碼(通常估計不會有人去直接閱讀IL查找問題吧)優化
JIT編譯器:
在 /optimize 關閉 的狀況下:
/debug - 關閉(默認) --> 有優化
/debug (+/full/pdbonly) --> 未優化:編譯器會生成PDB文件幫助編譯器查找到局部變量並將IL代碼映射到源代碼方便調試,若是指定的是
/debug : full 開關,編譯器還會記錄每一條IL指令生成的本機指令,但會使用額外的時間和內存
在 /optimize 開啓的狀況下:
/debug (-/+/full/pdbonly) --> 有優化spa
雖然編譯器在優化代碼的過程當中會佔用額外的時間和內存,可是在實際運行階段所帶來的收益遠遠大於這些犧牲,而且性能上遠遠大於非託管代碼,例如:
一、JIT編譯器針對不一樣的CPU優化本機代碼
二、會根據機器對特定的判斷進行代碼優化
三、CLR會根據運行狀態對代碼評估並從新編譯(還未實現).net
最後再來簡單瞭解一下NGen.exe工具
NGen.exe是.net framework提供的工具,它能夠將代碼提早編譯好,這樣JIT編譯器不須要在運行是編譯提高性能,但其實這個工具並非很實用
一、由於NGen沒法對代碼進行最優的優化 --> 由於沒法肯定CPU
二、對服務器提高不明顯 --> 由於只是在第一次運行時有幫助,後面運行的時間時相等的
三、可能失去同步 --> 若是當前代碼與執行環境不符合,那麼就會重新用JIT編譯debug
至此關於CLR如何與程序集工做就完成了,下一節咱們將介紹.net Framework的Framework 類庫以及CTS CLS調試