1. 程式人生 > >五、CLR加載程序集代碼時,JIT編譯器對性能的產生的影響

五、CLR加載程序集代碼時,JIT編譯器對性能的產生的影響

幫助 leaves 控制流程 斷點 繼續 操作系統 optimize visual image

1、CLR首次加載代碼造成的性能損失

四、CLR執行程序集中代碼介紹了CLR在首次執行一個類的時,會初始化一個內部結構,然後當目標方法被首次調用時,JITComplier函數(JIT編譯器)會驗證IL代碼並將IL代碼編譯成本地CPU指令並存儲到動態內存中,這意味著一旦應用程序終止,編譯好的代碼也會被丟棄,所以,當再次運行應用程序,或者同時啟動應用程序的兩個實例(使用兩個不同的操作系統的進程),JIT編譯器必須再次將IL編譯成本機指令.對於某些應用程序,這可能會增加內存的負擔.

相比之下,本機(native)應用程序的只讀代碼頁可由應用程序正在運行的所有實例共享.

2、CLR首次加載代碼造成的性能損失的嚴重程度

對於大多數應用程序,JIT編譯造成的損失並不嚴重,大多數應用程序都在反復的調用相同的方法。應用程序運行期間,這些方法只會對性能造成一次性的影響.除此之外,在方法內部花費的時間可能比花在首次調用方法,JIT編譯和優化IL所花費的時間更多.

3、CLR加載代碼時JIT編譯器進行的代碼優化

CLR首次加載程序集代碼時,JIT將IL編譯成本地代碼時,會對其進行代碼優化,這類似與非托管C++編譯器的後端所做的事情.這可能也會花費加多的時間生成優化代碼.

技術分享圖片

(1)、編譯器開關/optimize和/debug對代碼的影響

/optimize開關:

C#編譯器生成的未優化IL代碼,將包含許多NOP(空操作)指令,還將包含許多跳轉到下一行代碼的分支指令.Visual Stdio利用這些指令在調試提供"編輯並繼續"功能.另外,利用這些額外的指令,還可在控制流程指令(比如for,while,do,if,else,try,catch和finally)上設置斷點,使代碼更容易調試.相反,如果生成優化的IL代碼,C#編譯器會刪除多余的NOP和分支指令,而在控制流程被優化之後,代碼就不能再調試器中進行單步調試了。代碼若在調試器中執行,一些函數求值可能無法進行.但是,優化過的IL代碼變得更小,結果EXE/DLL文件也更小.

/debug(+/full/pdbonly)開關:

編譯器會生成Program Database(PDB)文件,PDB文件幫助調試器查找局部變量並將IL指令映射到源代碼.

/debug:full開關告訴JIT編譯器你打算調試程序集,那麽JIT編譯器會記錄每條IL指令所生成的本機代碼.這樣依賴,就可利用Visual Studio的“即時”調試功能,將調試器連接到正在運行的進程,並方便地對源代碼進行調試.

不打開/debug:full開關,JIT編譯器默認不記錄IL與本機代碼的聯系,這使JIT編譯器運行的稍快,占用內存也稍少.如果進程用Visual Stdio的“即時”調試功能,會強迫JIT編譯器記錄IL與本機代碼的聯系(無論編譯器的開關設置是什麽)除非在Visual Stdio中關閉了"在模塊加載時取消JIT優化(權限托管)"操作步驟如下:

工具-選項-調試

技術分享圖片

(2)、Visual Stdio中新建C#項目時,編譯器開關的默認設置

通過VS新建項目時,項目的調試(Debug)配置的是/optimize-和debug:full開關(IL代碼和本地代碼均未優化-方便調試),而"發布"(Release)配置置頂的是/optimize+和/debug:pdbpnly開關(IL代碼和本地代碼均優化-文件變小,占用內存小)

五、CLR加載程序集代碼時,JIT編譯器對性能的產生的影響