Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does Go have no real way to shrink a slice? Is that an issue?

Tags:

I've been trying out Go for some time and this question keeps bugging me. Say I build up a somewhat large dataset in a slice (say, 10 million int64s).

package main  import (     "math"     "fmt" )  func main() {     var a []int64     var i int64;     upto := int64(math.Pow10(7))     for i = 0; i < upto; i++ {         a = append(a, i)     }     fmt.Println(cap(a)) } 

But then I decide I don't want most of them so I want to end up with a slice of just 10 of those. I've tried both slicing and delete techniques on Go's wiki but none of them seem to reduce the slice's capacity.

So that's my question: does Go has no real way of shrinking the capacity of a slice that would be similar to realloc()-ing with a smaller size argument than in your previous call on the same pointer in C? Is that an issue and how should one deal with it?

like image 758
justinas Avatar asked May 25 '13 09:05

justinas


People also ask

How do slices work in Go?

A slice can also be formed by “slicing” an existing slice or array. Slicing is done by specifying a half-open range with two indices separated by a colon. For example, the expression b[1:4] creates a slice including elements 1 through 3 of b (the indices of the resulting slice will be 0 through 2).

Which function helps to increase the capacity of a slice in Go?

Use append to increase the length and capacity of a slice The append operation is clever when growing the capacity of the underlying array. For example, the capacity is always doubled when the existing capacity of the slice is under 1,000 elements.

How do I reset my slice in Go?

Setting the slice to nil is the best way to clear a slice. nil slices in go are perfectly well behaved and setting the slice to nil will release the underlying memory to the garbage collector. Note that slices can easily be aliased so that two slices point to the same underlying memory.

How do I find my slice size in Go?

The length and capacity of a slice s can be obtained using the expressions len(s) and cap(s) . You can extend a slice's length by re-slicing it, provided it has sufficient capacity. Try changing one of the slice operations in the example program to extend it beyond its capacity and see what happens.


2 Answers

To perform an, in effect, a realloc of a slice:

a = append([]T(nil), a[:newSize]...) // Thanks to @Dijkstra for pointing out the missing ellipsis. 

If it does a copy of newSize elements to a new memory place or if it does an actual in place resize as in realloc(3) is at complete discretion of the compiler. You might want to investigate the current state and perhaps raise an issue if there's a room for improvement in this.

However, this is likely a micro-optimization. The first source of performance enhancements lies almost always in selecting a better algorithm and/or a better data structure. Using a hugely sized vector to finally keep a few items only is probably not the best option wrt to memory consumption.

EDIT: The above is only partially correct. The compiler cannot, in the general case, derive if there are other pointers to the slice's backing array. Thus the realloc is not applicable. The above snippet is actually guaranteed to peform a copy of 'newSize' elements. Sorry for any confusion possibly created.

like image 164
zzzz Avatar answered Oct 21 '22 17:10

zzzz


Go does not have a way of shrinking slices. This isn't a problem in most cases, but if you profile your memory use and find you're using too much, you can do something about it:

Firstly, you can just create a slice of the size you need and copy your data into it. The garbage collector will then free the large slice. Copy built-in

Secondly, you could re-use the big slice each time you wish to generate it, so you never allocate it more than once.

On a final note, you can use 1e7 instead of math.Pow10(7).

like image 42
Dijkstra Avatar answered Oct 21 '22 18:10

Dijkstra