一、關於字符串操做對應用程序性能的影響html
字符串相等性檢查是應用程序常見的操做,於此同時,這也是一種嚴重損害性能的操做.執行序號(字符串的二進制)相等行檢查時,CLR會進行如下操做:函數
一、判斷字符串的長度是否相等,不相等,比較結果直接返回false,若是相等,繼續下一步操做post
二、比較字符串的長度相等,CLR會比較每一個單獨的字符才能最終肯定。而執行對語言文化敏感的比較時,CLR必須比較所 有單獨的字符,由於字符串即便長度不一樣也可能相等.性能
二、字符串留用 一 減小複製相同字符串實例對內存的消耗url
由於字符串的不可變性,若是應用程序常常對字符串進行區分大小寫的序號比較,這個時候若是你知道有許多字符串會有相同的值,那麼就能夠利用CLR的"字符串留用"機制來提高應用程序的性能.spa
原理:只保存相同字符串的一個實例來提高內存的利用率。將相同的字符串變量引用都指向一個字符串對象.code
三、CLR實現字符串留用的過程htm
CLR初始化時會建立一個內部哈希表.在這個表中,鍵(key)是字符串,而值(value)是對託管堆中的String對象的引用.這個過程相似與4、CLR執行程序集中代碼和IL代碼簡介 CLR第一次執行一個方法的過程相似,它會初始化一個內部結構,生成一系列的地址,地址指向JITComliler函數,該函數會將代碼轉成CPU指令等操做,並返回結果給調用的C#方法.對象
注:該哈希表最開始是空的.blog
String類提供了兩個方法便於你訪問這個內部哈希表:
(1)、Intern方法用於獲取一個String,得到它的哈希碼,並在哈希表中檢查是否有相匹配的,若是存在徹底相同的字符串,就返回對現有String對象的應用.若是不存在全完相同的字符串,就建立字符串的副本.將副本添加到內部哈希表中,返回對該副本的引用.若是應用程序再也不保持對原始String對象的引用,這時垃圾回收器就會介入,將字符串的內存強行釋放掉.
注:垃圾回收器不會釋放內部哈希表引用的字符串,由於哈希表正在容納對它們的引用.除非卸載AppDomain或進程終止,不然其內部哈希表應用的String對象不能被釋放.
(2)IsInterned方法也獲取一個String,並在內部哈西表中查找它.若是哈西表中有匹配的字符串,IsInterned方法就返回對這個留用字符串對象的應用.但若是沒有,IsInterned就返回null,不會將字符串添加到哈希表中.
四、CLR默認留用程序集元數據中的字面值字符串
程序集加載時,CLR默認留用程序集元數據中的描述的全部字面值字符串,大微軟知道這個過程可能由於額外的哈希表查找而顯著影響性能,因此如今能夠禁用此功能.經過對程序集用System.RunTime.ComiplerServices.CompilationRelaxationsAttribute進行了標記,並指定了System.RunTime.ComiplerServices.CompilationRelaxations.NoStringIntering標誌值.那麼根據ECMA規範,CLR可能選擇不留用指定程序集的元數據定義的全部字符串.爲了提高性能,C#編譯器在編譯程序集是老是指定上述連個特性和標誌.
五、CLR的4.5班版本及以上選擇忽略4中的特性和標誌,及顯示留用指定字符串
因爲CLR4.5及以上選擇忽略4中的特性,因此程序集加載到AppDomain中時,CLR會對該程序集中元數據中所描述的全部字面值字符串.代碼以下:
String str = "xiaochao"; String str1 = "xiaochao"; Console.WriteLine(ReferenceEquals(str,str1));//輸出:True
注:程序集加載到AppDomian中時,CLR對程序集中的元數據中的字面值字符串進行了留用,因此致使了"xiaochao"被留用,結果str和str1引用了堆中的同一個"xiaochao"字符串,可是咱們的代碼不能依賴這一行爲,由於將來的CLR版本可能會重視這些特性和標誌,到時候將不會對程序集元數據中的字面值字符串不進行留用.下面的代碼將顯示留用字符串,代碼以下:
//去內部哈希表中檢查是否有xiaochao字符串,有的話返回該字符串的引用,反之,建立該字符串的副本,返回該副本的引用. str = String.Intern(str); //去內部哈希表中檢查是否有xiaochao字符串,發現有xiaochao字符串,返回它的引用 str1 = String.Intern(str1); Console.WriteLine(ReferenceEquals(str, str1));//輸出:True
六、字符串池
編譯源代碼時,編譯器必須處理每一個字面值字符串,並在託管模塊中的元數據中嵌入.同一個字符串在源代碼中屢次出現,若是每次都去內存中重複開闢空間,不只浪費內存,並且把它們嵌入元數據會使生成的文件無謂的增大.
爲了解決這個問題,許多編譯器(包括C#編譯器)只在模塊的元數據中只將字面值字符串至寫入一次,CLR默認留用程序集元數據中的字面值字符串。引用改字符串的全部代碼都被修改爲引用元數據中的同一個字符串.編譯器將單個字符串的多個實例合併成一個實例,能顯著減小模塊的大小.C/C++編譯器多年來一直採用這個技術,這個技術被稱爲"字符串池".