熱點推薦:
您现在的位置: 電腦知識網 >> 編程 >> .NET編程 >> 正文

對 String 的幾個錯誤認識[1]

2022-06-13   來源: .NET編程 

  昨天調試一段程序發現內存始終釋放不掉最後終於發現是對String 的錯誤使用造成這促使我今天又仔細研究了一下String類型不研究不知道一研究發現我過去對String 的很多認識都是錯誤的感覺這種錯誤認識還比較有典型性於是寫下此文和大家一起探討

   String 類型變量追加或修改後的新String對象是駐留(Interned)的

   如下面代碼

string s = abcd;
string s = s + e;

   我過去想當然的認為s 是駐留的但實際上並非如此用 stringIsInterned 方法檢測s是非駐留的後來研究發現只有常量字符串才會默認駐留其他的字符串變量哪怕是采用 new string  構造出來的默認都非駐留除非用stringIntern 強行駐留後面我將提到駐留對內存的影響微軟之所以不讓所有的字符串都駐留我認為還是處於內存方面的考慮

   String 變量不再引用後CLR會通過GC自動釋放其內存

string s = abcd;
s = null;

  上面代碼我想當然的認為s = null 後已經不再對 abcd 這個字符串引用如果沒有其他引用指向這個字符串GC會釋放abcd這塊內存實際結果卻是否定的因為s 被賦予了一個常量導致 abcd這個字符串是駐留的駐留的字符串在進程結束之前無法被自動釋放更糟糕的是我昨天調試的那段程序裡面大量的字符串變量被采用 stringIntern 強制駐留這導致我把所有的托管對象都釋放了依然無法釋放那部分大概多M的內存

  Performance Considerations

  If you are trying to reduce the total amount of memory your application allocates keep in mind that interning a string has two unwanted side effects First the memory allocated for interned String objects is not likely be released until the common language runtime (CLR) terminates The reason is that the CLRs reference to the interned String object can persist after your application or even your application domain terminates Second to intern a string you must first create the string The memory used by the String object must still be allocated even though the memory will eventually be garbage collected

  The NET Framework version introduces the CompilationRelaxations::NoStringInterning enumeration member The NoStringInterning member marks an assembly as not requiring stringliteral interning You can apply NoStringInterning to an assembly using the CompilationRelaxationsAttribute attribute Also when you use the Native Image Generator (Ngenexe) to compile an assembly in advance of run time strings are not interned across modules

  看了英文的幫助就知道Intern 後的字符串是無法釋放的了

   兩個String如果引用不同只能用Equal 比較

   我一直想當然的認為 兩個String 類型如果用 == 操作符比較將比較其引用所以如果兩個String引用不同則只能使用Equal 來比較它們是否相等

   比如下面語句

string s = new StringBuilder()Append(My)Append(Test)ToString();
string s = new StringBuilder()Append(My)Append(Test)ToString();

   如下方法比較其引用

ConsoleWriteLine((object)s == (object)s);

   得到結果為 false即s s指向不同引用

   那麼我想當然的認為  ConsoleWriteLine(s == s); 的結果也是false因為string 是引用類型用==操作符比較引用類型變量如果兩個變量的引用不同即便值相同也會返回false 然而運行的結果讓我大跌眼鏡返回的值是true

   於是在網上狂搜最後終於找到了原因

   String 的等號操作符的處理是特殊的其源碼如下

=== Equality operator on string type (C#) ===

// The == operator overload MSIL:
method public hidebysig specialname static bool
    op_Equality(string a string b) cil managed
{
    maxstack
    L_: ldarg
    L_: ldarg
    L_: call bool SystemString::Equals(
        string string)
    L_: ret
}

[]  []  


From:http://tw.wingwit.com/Article/program/net/201311/15387.html
    推薦文章
    Copyright © 2005-2022 電腦知識網 Computer Knowledge   All rights reserved.