I've noticed an unexpected behavior when appending elements to slices of different integer types (int32
and int64
) in Go. Specifically, the initial capacities assigned to these slices appear to differ based on the type, despite appending the same number of elements.
For instance, when I initialize a slice and append an element using the variadic append function, the capacities differ:
s1 := []int64{}
s2 := []int32{}
s1 = append(s1, []int64{0}...) // len:1, cap:1
s2 = append(s2, []int32{0}...) // len:1, cap:2
And similarly, when appending three elements:
s1 = append(s1, []int64{1, 2, 3}...) // len:3, cap:3
s2 = append(s2, []int32{1, 2, 3}...) // len:3, cap:4
However, when I append elements incrementally, both slices exhibit the same growth pattern:
s1 := []int64{}
s2 := []int32{}
s1 = append(s1, 1) // len:1, cap:1
s1 = append(s1, 2) // len:2, cap:2
s1 = append(s1, 3) // len:3 cap:4
s2 = append(s2, 1) // len:1, cap:2
s2 = append(s2, 2) // len:2, cap:2
s2 = append(s2, 3) // len:3 cap:4
Can someone explain why Go's append function assigns different capacities to slices of different types (int32
vs. int64
) when elements are appended in groups, but not when appended one at a time? Is this behavior documented somewhere, or is it an implementation detail of the runtime?
As has been mentioned in comments, this will relate to memory alignment and the word size of the architecture you are using.
On a 64-bit platform the CPU registers will be 64 bits (or 8-bytes) in size. The standard int
type will be 64 bits, as will pointers, and 64-bit floats are probably going to be the most commonly used too.
That's an awful lot of data moving around in 8-byte chunks, so all manner of aspects of the architecture may be optimised for working with 8 byte chunks of memory. You should see a similar pattern with int8
slices jumping from 0
to 8
capacity, and int16
slices jumping from 0
to 4
.
It's worth considering that the underlying array data is heap allocated, and if we allocate 4 bytes of memory for a growing []int32
, then there is a 4-byte space which is not correctly aligned for those 8-byte integers, pointers, and floats, so the heap manager will leave that gap when allocating space as we dump more of them onto the heap. Those extra 4 bytes aren't likely to be especially useful at best, and at worst are going to contribute towards heap fragmentation.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With