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

时间:2013-01-17 20:42:01

标签: string garbage-collection go slice

根据这篇Go Data Structures文章,在 Strings 部分下,它指出采取一个字符串片段会将原始字符串保留在内存中。

  

“(另外,在Java和其他语言中有一个众所周知的问题,当你切割一个字符串以保存一小块时,对原始文件的引用会将整个原始字符串保留在内存中,即使只有少量仍然需要.Go也有这个问题。我们尝试和拒绝的替代方案是使字符串切片如此昂贵 - 分配和副本 - 大多数程序都避免它。)“ < / p>

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

s := "Some very long string..."

我们采取一小部分:

newS := s[5:9]

在我们发布s之前,我们不会发布原始newS。考虑到这一点,如果我们需要保持newS长期,但释放s进行垃圾收集,采取什么方法?

我想也许这样:

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

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

2 个答案:

答案 0 :(得分:5)

是的,转换为一个字节片段将创建一个字符串的副本,因此原始字符串不再被引用,并且可以在某个地方进行GC。

作为这个的“证明”(好吧,它证明了字节切片不与原始字符串共享相同的底层数据):

http://play.golang.org/p/pwGrlETibj

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

http://play.golang.org/p/3pwZtCgtWv

Edit2:你可以清楚地看到内存分析会发生什么。在reuseString()中,使用的内存非常稳定。在copyString()中,它会快速增长,显示由[]字节转换完成的字符串副本。

http://play.golang.org/p/kDRjePCkXq

答案 1 :(得分:2)

在切片并保持切片“实时”之后,确保字符串最终可能有资格进行垃圾收集的正确方法是创建切片的副本并保持“实时”复制。但现在人们正在以更糟糕的时间性能为代价购买更好的内存性能。在某个地方可能会很好,但在其他地方可能会evil。有时只有适当的测量,而不是猜测,才会告诉真正的增益。

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