String 切片后释放字符串进行垃圾回收的正确方法

String 切片后释放字符串进行垃圾回收的正确方法,string,garbage-collection,go,slice,String,Garbage Collection,Go,Slice,根据本文,在Strings部分下,它声明获取字符串的一个片段会将原始字符串保留在内存中 "(顺便说一句,Java和其他语言中有一个众所周知的gotcha,当你切片一个字符串以保存一小段时,对原始字符串的引用会将整个原始字符串保留在内存中,即使只需要少量。Go也有这个gotcha。我们尝试过并拒绝的另一种方法是让字符串切片变得如此昂贵这是大多数程序避免的分配和副本。)” 如果我们有一个很长的字符串: s := "Some very long string..." 我们来分一小片: newS :=

根据本文,在Strings部分下,它声明获取字符串的一个片段会将原始字符串保留在内存中

"(顺便说一句,Java和其他语言中有一个众所周知的gotcha,当你切片一个字符串以保存一小段时,对原始字符串的引用会将整个原始字符串保留在内存中,即使只需要少量。Go也有这个gotcha。我们尝试过并拒绝的另一种方法是让字符串切片变得如此昂贵这是大多数程序避免的分配和副本。)”

如果我们有一个很长的字符串:

s := "Some very long string..."
我们来分一小片:

newS := s[5:9]
原始的
s
在我们发布
newS
之前不会发布。考虑到这一点,如果我们需要长期保存
newS
而发布
s
进行垃圾收集,那么正确的方法是什么

我想也许是这样:

newS := string([]byte(s[5:9]))

但我不确定这是否真的有效,或者是否有更好的方法。

是的,转换为字节片将创建字符串的副本,因此原始字符串不再被引用,并且可以在行的某个位置进行GCed

作为这方面的“证明”(它证明字节片与原始字符串不共享相同的底层数据):

编辑:并证明字节片只有必要的长度和容量(换句话说,它的容量不等于原始字符串的容量):

Edit2:您可以清楚地看到内存分析的结果。在reuseString()中,使用的内存非常稳定。在copyString()中,它增长很快,显示了通过[]字节转换完成的字符串副本


确保字符串在切片并保持切片“活动”后最终有资格进行垃圾收集的正确方法是创建切片的副本并保持“活动”而是复制。但现在人们正在以时间性能恶化为代价购买更好的内存性能。可能在某个地方是好的,但可能在其他地方。有时只有正确的测量,而不是猜测,才能知道真正的收益在哪里


例如,我在使用,当我喜欢一点邪恶;-)

在你的例子中,新的
[]字节被分配给变量而不是像我一样内联,这会有什么不同吗?不,请参阅我答案中的第二个编辑(通过内存统计进行验证)。上一个Go问题(和答案)是关于这种行为的,所以你可能想看看谢谢。是的,我想的是这样一种情况,从一根大绳子上切下一小片,否则就不需要了。我主要想知道正确的技术。我看到StrPack使用了相同的东西。再次感谢。你的意思是
新闻:=StrPack(s[5:9])
?;-)应该注意的是,Java放弃了这种优化,因为与用户代码中添加的bug相比,这种优化的收益太低了。看这个。在围棋中,问题是不同的,因为数组切片有一个非常特定的语义,应该作为语言的基础来学习。