編譯器將C#/F#/VB.net源代碼和資源文件打包爲程序集。程序集內包含託管的模塊和資源文件。託管的模塊中PE32/PE32+頭文件記載了與本機CPU代碼有關的信息。若是爲純IL代碼的模塊,PE32/PE32+一般被忽略。CLR頭一般記錄了CLR版本、Main方法的信息以及模塊的信息和一些數據,咱們可使用CLRVer.exe
命令查詢到CLR版本,參數爲-all
所有,進程ID
指定進程。架構
咱們能夠在Visual Studio設置目標平臺信息:併發
IL代碼雖然被稱爲一種彙編,可是看起來彷佛IL比常說的x86彙編簡單不少。這種代碼將會在程序第一次(而非首次)執行的時候首先讀取目標的IL代碼而後生成機器碼而後修改目標節點的引用指向生成的機器碼,當機器碼生成結束後程序執行的就是機器碼,由於全部的引用都被修改指向了即時生成的機器碼。因此託管代碼編寫的程序僅在第一次執行(而非首次)的時候慢一點,然後就能全速運行。ide
這種即時編譯(JIT)的技術Java目前也在使用,彷佛咱們看起來使用JIT技術會致使程序性能有點糟糕,但實際上效率可能比本身寫的非託管代碼的效率還高。咱們都知道編譯器在編譯時期會執行優化操做讓程序的運行速度更快,可是編譯器編譯出來的程序可能在某一具體架構上不一樣型號的處理器運行,爲了確保不出現Intel Pentium、Intel Core i三、Intel Core i五、Intel Core i七、Intel Atom、AMD Opteron等奇葩的版本出現,那麼編譯器將會以最小處理器指令集編譯,這樣兼容性確保了,可是新的指令集的優點彷佛就沒有利用到。函數
JIT在編譯的時候可以知道某臺計算機是否具備新的指令集可使用,一旦可用那麼它會使用新的指令集,這樣,利用新的指令集就可能帶來速度的提高。工具
同時對於自己不能執行的代碼(永假),JIT能夠選擇不予編譯,因此在相似要求AMD處理器的IL代碼段在程序運行的時候並不會被編譯爲機器碼。這樣亦可提供速度的提高。性能
因此本身的非託管代碼的編寫能力沒有達到必定程度,託管的代碼可能效率更高。優化
.NET也提供了NGen.exe工具來編譯IL代碼爲機器碼並保存爲一個文件,首次加載的時候會檢查該文件是否符合運行要求的版本,若是符合那麼能夠直接運行該文件而避免JIT,可是這樣可能喪失JIT帶來的優點,由於NGen.exe生成的代碼不得不考慮最小運行環境。ui
若是有多處理器,那麼可使用System.Runtime.ProfileOptimization類來優化。它會讓CLR檢查程序運行時哪些方法被JIT編譯,並將結果記錄到一個文件。程序再次啓動時,就用其餘線程併發編譯這些方法。這樣應用程序運行得更快,由於多個方法併發編譯,並且是在應用程序初始化時編譯,而不是在用戶和程序交互時才「即時」編譯。加密
至於有人爲了保護本身的知識產權使用NGen.exe生成的機器代碼發佈,實際上是不能的。縱使NGen.exe生成了一份機器碼,可是基於.NET的程序依然會隨附一份IL彙編代碼以確保在機器碼出現問題的時候不會致使程序Crash。.net
因爲.NET利用了JIT,如今的.NET反編譯的反編譯後的代碼質量至關高,因此咱們經常使用的保護知識產權的辦法是代碼混淆。使用代碼混淆器將本身寫的程序混淆加密,加大反編譯後閱讀的難度。有趣的是彷佛這些反編譯工具(ILDASM.EXE)除外都不能將F#編寫的程序文件正確逆向工程。曾嘗試使用F#寫過一個SqlHelper動態連接庫,代碼混淆後再使用了三款反編譯工具都沒能正確逆向出F#代碼,即便逆向出來的C#代碼也只有函數名而不包含函數體,在整個導出文件夾內的文件中沒可以找到函數體。因此若是依然想使用.NET來撰寫且不但願透露代碼邏輯的,能夠嘗試F#這門語言。
前面說道NGen.exe產生的文件是不能夠發佈給用戶的,可是針對大型程序咱們仍是能夠利用NGen.exe來優化的,固然這裏的大型程序不包括Web應用程序,由於Web應用程序僅在第一次訪問的時候須要JIT,然後就不須要JIT了。使用Managed Profile Guided Optimization工具來檢查啓動的時候須要執行那些東西,而後反饋給NGen.exe優化產生的本機代碼鏡像,發佈前使用MPGO.exe走一邊流程後將profile文件整合進程序集,NGen.exe將會利用它來建立更佳的本機鏡像。