A Go slice stores its elements in a backing array. The slice holds a pointer to that array, a length, and a capacity. Length limits which elements can be accessed; capacity describes the available space in the array. Confusing the two can cause unexpected writes, allocations, or retained memory. section 3.4
Two slices, one array
With `s1 := make([]int, 3, 6)` and `s2 := s1[1:3]`, the slices share a backing array. Changing a common element through either slice is visible through both. An `append` may also write into that shared array while capacity remains; once it is full, Go creates another array and copies the elements. section 3.4
Choose an approach based on the problem:
- When the result size is known, use `make([]T, 0, n)` before appending, or `make([]T, n)` and assign by index. This avoids repeated backing-array allocations and copies. section 3.5
- When retaining a small part of a large `[]byte`, copy it into a new slice. Returning `msg[:5]` can keep the entire message array alive; `msg[:5:5]` limits capacity but does not make the remaining storage reclaimable. section 3.10.1
- When discarding elements containing pointers or slice fields, copy the wanted elements or clear the unwanted references before slicing. Reducing length alone does not release what those elements reference. section 3.10.2
func main() {
foos := make([]Foo, 1_000) #1
printAlloc()
for i := 0; i < len(foos); i++ { #2
foos[i] = Foo{
v: make([]byte, 1024*1024),
}
}
printAlloc()
two := keepFirstTwoElementsOnly(foos) #3
runtime.GC() #4
printAlloc()
runtime.KeepAlive(two) #5
}
func keepFirstTwoElementsOnly(foos []Foo) []Foo {
return foos[:2]
}
The two-element result still references the original array of 1,000 structs. After garbage collection, the allocations referenced by the other elements remain retained. section 3.10.2
A slice assignment is not a copy of its elements: both slices still reference the same array. This matters across goroutines. Concurrent `append` calls to a full slice receive separate arrays; calls with spare capacity can write the same backing-array index and race. Copy first when each goroutine needs isolated storage. section 9.10 section 9.9
The retention risk also appears with strings: with the standard Go compiler, storing a short substring of a large log can retain the original backing array. Make a separate copy when the substring must outlive the log. section 5.6


