【问题标题】:WeakReference wrapping a string causes strange behavior包装字符串的 WeakReference 会导致奇怪的行为
【发布时间】:2015-07-16 23:21:06
【问题描述】:

我知道我应该只对大型对象使用 Wea​​kReference,但我对以下场景感到好奇:

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?

发生了什么事?

【问题讨论】:

    标签: c#


    【解决方案1】:

    来自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
    

    【讨论】:

    • 太棒了,迈克 z!非常感谢!
    • 我在我的程序集信息上应用了以下属性:CompilationRelaxationsAttribute(CompilationRelaxations.NoStringInterning)] 我的代码继续返回相同的结果。这应该不会影响我们的结果吗?
    • @ViniciusGonçalves 我不熟悉那个属性,但other questions 建议这不是保证,只是一个提示。
    【解决方案2】:

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

    【讨论】:

    • 完美,服务!非常感谢!
    猜你喜欢
    • 1970-01-01
    • 2019-08-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-02-27
    • 1970-01-01
    • 2013-12-23
    相关资源
    最近更新 更多