4

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

“(顺便说一句,在 Java 和其他语言中有一个众所周知的陷阱,当您对字符串进行切片以保存一小段时,对原始字符串的引用会将整个原始字符串保留在内存中,即使只有一小部分仍然存在需要。Go 也有这个问题。我们尝试并拒绝的替代方案是让字符串切片变得如此昂贵——分配和复制——大多数程序都避免它。)”

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

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

我们取一小部分:

newS := s[5:9]

在我们也发布之前,原版s不会发布newS。考虑到这一点,如果我们需要newS长期保留,但要释放s垃圾收集,应该采取什么正确的方法?

我想也许是这样的:

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

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

4

2 回答 2

5

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

作为对此的“证明”(好吧,它证明了字节切片与原始字符串不共享相同的基础数据):

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

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

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

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

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

于 2013-01-17T20:55:12.207 回答
2

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

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

于 2013-01-17T21:38:15.637 回答