这是否会导致旧的字符串对象被垃圾收集,或者它仍然是对同一对象的相同引用?
string str = "Hello World!";
str = str.ToUpper();
我理解GC的作用及其不可预测性。
答案 0 :(得分:6)
这是否会导致旧的字符串对象被垃圾回收
我们不能说。有两个原因:
还是对同一个对象仍然是相同的引用?
没有。您创建了一个新字符串。 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/