Everton
Everton

Reputation: 13825

Can this type of golang string slicing leak memory in underlying byte array?

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

Upvotes: 4

Views: 2804

Answers (2)

Mr_Pink
Mr_Pink

Reputation: 109337

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.

Upvotes: 5

kostya
kostya

Reputation: 9559

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.

Upvotes: 3

Related Questions