调用ToUpper()等后,旧的字符串对象是否会被垃圾回收?

时间:2018-03-31 19:54:51

标签: c# garbage-collection

这是否会导致旧的字符串对象被垃圾收集,或者它仍然是对同一对象的相同引用?

    string str = "Hello World!"; 
    str = str.ToUpper();

我理解GC的作用及其不可预测性。

4 个答案:

答案 0 :(得分:6)

  

这是否会导致旧的字符串对象被垃圾回收

我们不能说。有两个原因:

  1. 我们不知道是否有其他对字符串的引用。如果对字符串有其他引用,则该字符串将不符合收集条件。注意:如果您显示的代码是整个代码,则不会有其他引用。
  2. 即使字符串符合垃圾收集条件,也无法知道垃圾收集器何时运行。我们甚至不知道垃圾收集器是否会运行。
  3.   

    还是对同一个对象仍然是相同的引用?

    没有。您创建了一个新字符串。 The documentation 明确表明(粗体强调我的):

      

    返回此字符串转换为大写的副本

      

    注意:此方法不会修改当前实例的值。相反,返回一个新字符串,其中当前实例中的所有字符都转换为大写。

    此外,string是不可变的,因此无论如何都无法更改。

答案 1 :(得分:5)

是的,旧的字符串对象最终会被垃圾收集,GC会发现没有更多对该对象的引用

经过一些研究,似乎字符串文字,例如"Hello World!"默认是临时的,所以即使不再提及它们,也不会像@Henk Holterman在评论中提到的那样对它们进行垃圾收集。

这是因为字符串文字是程序集的一部分,并且没有垃圾收集。

所以,我现在将上面的段落改为:

是的,如果它不是字符串文字,旧的字符串对象将被垃圾收集,GC最终会发现没有对该对象的引用

但是, GC执行此操作时非确定性

答案 2 :(得分:0)

我们无法谈论GC在任何特定时间做什么和不做什么。基于强烈的推荐,我们只能在任何特定时间谈论可以做什么。当然还有String,会有很多特殊处理进入房间。

一般规则是" GC可以收集任何没有完整的对Root References"的强引用链的东西。通过设计,字符串已经变得无法改变。它不是类的常见行为,但在多线程方案中具有优势。所以ToUpper()确实会尝试创建一个与旧的字符串实例无关的新字符串实例。只要您停止对旧字符串的引用,就可以原始一瞥,它应该符合垃圾收集的条件。

除外:字符串实习。由于字符串的不可替换性质会导致过多的内存分配(每个connaction操作都会在内存中留下一个垃圾字符串),因此会有一个机制调用" string interning"到位。基本上,框架具有已分配的所有字符串的列表。如果你尝试两次分配相同的字符串,那么你在内存中已经拥有的实例将被重新使用。不会有新实例,但会重复使用实例。

如果你写了字符串" Hellow World"在100个标签上,编译器优化和实习之间存在一个很大的机会,实际上只有一个字符串" Hello World"在内存中分配。通常,String Interning的内存优化非常好。但是当你需要解决它(以及其他关于字符串的自动化/属性)时,他们为此发明了一个额外的类 - StringBuilder

答案 3 :(得分:-1)

另一个仅针对String类型而非其他类型的细节是实习。基本上,由于字符串被如此使用,运行时将只存储所使用的每个String值的一个副本,并且由于字符串是不可变的,因此对相同值的字符串的任何引用都将是对同一实例的引用。见https://www.c-sharpcorner.com/UploadFile/d551d3/what-is-string-interning/