包装字符串的WeakReference会导致奇怪的行为

时间:2015-05-06 17:07:21

标签: c#

我知道我应该仅针对大型对象使用WeakReference,但我对以下场景感到好奇:

object obj = 1; //Int32

var wk = new WeakReference(obj);

Console.WriteLine(wk.IsAlive); //Prints: True

obj = null;

GC.Collect(2, GCCollectionMode.Forced, true);

Console.WriteLine(wk.IsAlive); //Prints: false, All Rigth!

到目前为止,没关系。

看看这个:

object obj = "test"; //String

var wk = new WeakReference(obj);

Console.WriteLine(wk.IsAlive); //Prints: True

obj = null;

GC.Collect(2, GCCollectionMode.Forced, true);

Console.WriteLine(wk.IsAlive); //Prints: True, Why?

发生了什么事?

2 个答案:

答案 0 :(得分:6)

来自String.Intern的评论:

  

公共语言运行库通过维护一个名为intern pool的表来保存字符串存储,该表包含对程序中以编程方式声明或创建的每个唯一文字字符串的单个引用。因此,具有特定值的文字字符串实例仅在系统中存在一次。

因此,您无法以编程方式发布另一个引用。稍微更改代码以在运行时生成实例会得到预期的结果:

object obj = new string(new char[] { 't', 'e', 's', 't' });
var wk = new WeakReference(obj);
Console.WriteLine(wk.IsAlive); //Prints: True
obj = null;
GC.Collect(2, GCCollectionMode.Forced, true);
Console.WriteLine(wk.IsAlive); //Prints: False

答案 1 :(得分:5)

字符串是一个编译时文字,因此除非在编译代码时关闭编译时文字的自动实习(默认情况下它会打开),所有编译时字面字符串都将保存在查找表中,防止它们在应用程序的整个生命周期内被GC。