英文:
Can this type of golang string slicing leak memory in underlying byte array?
问题
golang的字符串切片操作buf = buf[n:]
会导致底层字节数组的内存泄漏吗?
如果会导致内存泄漏,是否有可能获取有关底层字节数组的信息(如容量或基本内存地址),以验证内存泄漏?
请参考下面的示例代码:
var buf string
func push(s string) {
buf += s
if len(buf) > 3 {
buf = buf[len(buf)-3:] // 这行代码会导致底层字节数组的内存泄漏吗?
}
fmt.Printf("buf=[%v]\n", buf)
}
英文:
Can golang string slicing like buf = buf[n:]
cause memory leak in the underlying byte array?
If so, is it possible to get any information (like capacity, or base memory address) about the underlying byte array, in order to verify the leak?
Please see sample code below:
var buf string
func push(s string) {
buf += s
if len(buf) > 3 {
buf = buf[len(buf)-3:] // can this line leak memory in underlying byte array?
}
fmt.Printf("buf=[%v]\n", buf)
}
[Run it on playground][1]
[1]: http://play.golang.org/p/ad2_j2eGQh "Playground"
答案1
得分: 5
不,这个例子不会导致内存泄漏,因为每次调用push
时都需要分配新的字符串。可能会有一些字节在某些时候保留下来以减少分配,但这是一个实现细节,不应该考虑进去。
如果你在考虑类似的情况,即在分配结果后没有进行追加的情况下可能出现的情况。严格来说,并没有泄漏,只要你理解切片的语义。
s := make([]byte, 1024)
s = s[1000:]
fmt.Println(s, len(s), cap(s))
这个例子会保留前1000个字节的分配空间,但无法访问。解决这个问题很简单,不要这样做。避免这种情况并不难,如果确实需要释放底层数组,可以使用copy
将字节移动到一个新的切片中。
对于字符串也是一样的:
s = s[1020:]
// 可能会保留前1000个字节的分配空间
这个问题也很容易理解和避免。如果你使用的是大型字符串,最好使用[]byte
,这样你可以更好地控制分配,并在需要时复制字节。
英文:
No, this example can't cause a memory leak, since you need to allocate new strings each time you call push
. It's possible that some bytes will be kept around at times to reduce allocations, but how that works is an implementation detail that shouldn't be taken into consideration.
If you're thinking of a similar situation which can arise when you assign a result of a slice operation, but never append. There's no leak per say, as long as you understand the semantics of slicing.
s := make([]byte, 1024)
s = s[1000:]
fmt.Println(s, len(s), cap(s))
This example will leave the first 1000 bytes allocated, but inaccessible. The answer to this is simple, don't do that. It's not hard to avoid, and if you do need to ensure that you've released the underlying array, use copy
to move the bytes to a new slice.
This works the same with strings:
s = s[1020:]
// may leave the first 1000 bytes allocated
This is again fairly easy to see what's going on, and avoid. If you're using huge strings, you're often better off using []byte
anyway, where you have better control over allocation, and can copy the bytes when needed.
答案2
得分: 3
将字符串应用切片表达式p := s[i:j]
的结果是一个字符串。据我所知,Go语言规范(https://golang.org/ref/spec)没有指定p
将由与s
相同的内存支持。
然而,在Go 1.6及更早版本中,对p
的活动引用会阻止s
被垃圾回收。然而,这在将来的Go版本中可能会发生变化。
有趣的是,在Java中,直到Java 8,String.substring
方法也是以相同的方式实现的。然而,在Java 8中,substring
返回一个副本。
回到你的例子。每次调用push
函数时,以下代码实际上会创建一个新的字符串实例:
buf += s
旧的buf
实例会被垃圾回收。因此,你的例子不会受到上述问题的影响。
英文:
A result of applying slice expression to a string in p := s[i:j]
is a string. As far as I can tell the Go language specification (https://golang.org/ref/spec) doesn't specify that p
will be backed by the same memory as s
.
However it looks like in Go 1.6 and earlier versions a live reference to p
will hold s
from being garbage collected. This might however change in the future versions of Go.
An interesting fact that in Java String.substring
method was implemented in the same way until Java 8. In Java 8 however substring
returns a copy.
Back to your example. The following line actually creates a new string instance every time you call push
function:
buf += s
The old instance of buf gets garbage collected. So your example is not affected by the problem described above.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论