CLR Via C# 学习笔记(5) 静态构造函数的性能
CLR Via C#》這本書以前就粗略看過兩遍,但一直都沒能深入理解,而且很多內容也忘記了,現在準備重新看一遍,并將看過的部分寫出來,因為寫的過程也是一個加深理解的過程。本系列算是學習的一個記錄吧,也可以方便以后自己查閱,如果對大家還有些幫助的話,我就很高興了。書我是選擇性的看的,所以順序和書中的順序可能不一樣。
在上一篇《CLR Via C# 學習筆記(4) 方法 構造函數 》中講到了一些靜態構造函數方面的知識,現在也回顧一下,大概總結如下:
- 靜態構造函數是私有的(private) ,而且不能人為去修改訪問修飾符。
- 靜態構造函數不應該去調用基類的靜態構造函數,因為靜態字段不會被繼承到子類。
- 靜態構造函數在一個類型中有且僅有一個,并且是無參的。
- 靜態構造函數中只能初始化靜態字段。
從上面的第一點可以知道靜態構造函數都是private的,所以不能顯示區進行調用,關于JIT何時會去生成調用靜態構造函數的代碼。存在著兩種說法。通常被稱為Precise和BeforeFieldInit。
l Precise方式JIT編譯器生成調用的時機:首次創建類型的代碼之前;訪問類的非繼承字段或成員代碼之前。
l BeforeFieldInit方式JIT編譯器生成調用的時機:在訪問費繼承靜態字段代碼之前。
這兩種方式的主要區別就是選擇調用靜態構造函數的時機是否是確定的,Precise方式CLR會在確定的時刻調用靜態構造函數,而BeforeFieldInit方式CLR可以自由選擇調用靜態構造函數的時機,利用這一點,CLR可以根據類型是否在程序域中加載來選擇靜態構造函數的調用次數,以便能生成執行更快的代碼。
下面來看來個類分別展現了這兩種方式
public classUserPrecise {public static string_name = "內聯賦值:oec2003";staticUserPrecise(){_name = "構造函數賦值:oec2003";} } public classUserBeforeFieldInit {public static string_name = "內聯賦值:oec2003"; }通過IL代碼可以看出在UserBeforeFieldInit 的元數據上有BeforeFieldInit的標記,如下圖:
?
既然上面提到BeforeFieldInit方式CLR可以選擇調用構造函數的次數從而來生成執行更快的代碼,下面就寫一段測試代碼來看看究竟怎樣。
public sealed class Program {static void Main(string[] args){const Int32 iterations = 1000 * 1000 * 1000;Test1(iterations);Test2(iterations);}private static void Test1(Int32 iterations){Stopwatch sw = Stopwatch.StartNew();for (Int32 i = 0; i < iterations; i++){UserBeforeFieldInit._name = "oec2003";}Console.WriteLine("Test1-UserBeforeFieldInit 用時:" + sw.Elapsed);sw = Stopwatch.StartNew();for (Int32 j = 0; j < iterations; j++){UserPrecise._name = "oec2003";}Console.WriteLine("Test1-UserPrecise 用時:" + sw.Elapsed);}private static void Test2(Int32 iterations){Stopwatch sw = Stopwatch.StartNew();for (Int32 i = 0; i < iterations; i++){UserBeforeFieldInit._name = "oec2003";}Console.WriteLine("Test2-UserBeforeFieldInit 用時:" + sw.Elapsed);sw = Stopwatch.StartNew();for (Int32 j = 0; j < iterations; j++){UserPrecise._name = "oec2003";}Console.WriteLine("Test2-UserPrecise 用時:" + sw.Elapsed);} }public class UserBeforeFieldInit {public static string _name; }public class UserPrecise {public static string _name;static UserPrecise(){_name = "oec2003";} }測試結果如下:
?
從上面結果來看,BeforeFieldInit方式的執行速度還是要快很多,但為什么第二次執行時,兩種方式的速度差不多呢?因為經過第一次執行后JIT編譯器知道類型的構造器已經被調用了,所以第二次執行時不會顯示對構造函數進行調用。
系列相關文章
CLR Via C# 學習筆記(1) 基元類型 值類型 引用類型
CLR Via C# 學習筆記(2) 裝箱和拆箱
CLR Via C# 學習筆記(3) 常量和字段(cosnt readonly)
CLR Via C# 學習筆記(4) 方法 構造函數
CLR Via C# 學習筆記(5) 靜態構造函數的性能
CLR Via C# 學習筆記(6) 方法參數相關(out ref params)
轉載于:https://blog.51cto.com/oec2003/1043876
總結
以上是生活随笔為你收集整理的CLR Via C# 学习笔记(5) 静态构造函数的性能的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 大学生想要通过看书自学编程,却始终没成功
- 下一篇: [免费]开源制衣公司网站源程序 (三)!