本次字串拘留實驗分為4個,最終根據實驗得出了一個很有意思的結論。這些結論使兄弟們在以前關於字串操作的結論基礎上進行深入理解。(關於字串拘留池,請Google一下String Intern Pool,你可以搜尋到不少東西的。)
1 在Main中沒有出現硬字串
string a1 = new string('a', 1);
string a2 = new string('a', 1);
Console.WriteLine(a1);
Console.WriteLine(string.IsInterned(a1) != null);
Console.WriteLine(ReferenceEquals(a1, a2));
> a
> False
> False
2 在Main中出現硬字串
string a1 = new string('a', 1);
string a2 = new string('a', 1);
Console.WriteLine(a1);
Console.WriteLine(string.IsInterned(a1) != null);
Console.WriteLine(string.IsInterned("a") != null);
Console.WriteLine(ReferenceEquals(a1, a2));
> a
> True
> True
> False
注意:為什麼第一個IsInterned竟然得出a已經拘留了呢?呵呵。
3 在Main中不出現硬字串,但在另一個類出現硬字串,不過另一個類沒有被使用
// a1 和 a2都不在拘留池,且地址不一樣。
string a1 = new string('a', 1);
string a2 = new string('a', 1);
Console.WriteLine(a1);
Console.WriteLine(string.IsInterned(a1) != null);
Console.WriteLine(ReferenceEquals(a1, a2));
class StringInternPoolTest1
{
public StringInternPoolTest1()
{
string a1 = new string('a', 1);
Console.WriteLine(string.IsInterned(a1) != null);
string a = "a";
}
}
> a
> False
> False
4 在Main中不出現硬字串,但使用了另一個具有硬字串的類
string a1 = new string('a', 1);
string a2 = new string('a', 1);
Console.WriteLine(a1);
Console.WriteLine(string.IsInterned(a1) != null);
Console.WriteLine(ReferenceEquals(a1, a2));
StringInternPoolTest1 test = new StringInternPoolTest1();
class StringInternPoolTest1
{
public StringInternPoolTest1()
{
string a1 = new string('a', 1);
Console.WriteLine(string.IsInterned(a1) != null);
string a = "a";
}
}
> a
> False
> False
> True
本次實驗結論:
1 只有硬字串才能被拘留;
2 當JIT編譯方法後,執行前會將一個方法的所有硬字串拘留;
3 string x = "a" 不會執行記憶體分配,原因很簡單,在該語句之前JIT已經執行字串拘留,即JIT提前分配了字串的所需的記憶體以及字串拘留池項。
其它待實驗論點:
1 只有CLR執行結束,拘留字串才能被釋放;
2 拘留一個字串的行為為將引用新增到CLR的一個Hashtable,它始終對字串進行引用,從而阻止GC對拘留字串進行回收;
3 編譯器的優化行為(大家可以猜測一下如何優化,呵呵)。