弱引用包装字符串会导致奇怪的行为

3

我知道应该只在处理大对象时使用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个回答

6

根据 String.Intern 的说明:

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

因此,有另一个引用无法通过编程方式释放。稍微更改代码以在运行时生成实例即可获得预期结果:

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

太棒了,Mike Z!非常感谢! - Vinicius Gonçalves
我在程序集信息中应用了以下属性:CompilationRelaxationsAttribute(CompilationRelaxations.NoStringInterning)]但我的代码仍然返回相同的结果。这不应该对我们的结果产生影响吧? - Vinicius Gonçalves
1
@ViniciusGonçalves 我不熟悉那个属性,但是其他问题[(https://dev59.com/CHDXa4cB1Zd3GeqP8BK_)表明它不是一个保证,只是一个提示。 - Mike Zboray

5
该字符串是一个编译时文本,因此除非在编译代码时关闭编译时文字的自动合并(默认情况下会开启),否则所有编译时文字字符串都将被保存在查找表中,导致它们在应用程序的整个生命周期内无法进行垃圾回收。

太完美了,Servy!非常感谢! - Vinicius Gonçalves

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接