Go Benchmark
Slice Preallocation
How much does preallocating slice capacity actually save?
Growing a slice with append from nil looks harmless, but every time the backing array runs out of capacity the runtime allocates a bigger one and copies all existing elements over. This benchmark builds a slice of 10,000 integers three ways: appending to a nil slice, appending into a slice preallocated with make([]int, 0, n), and writing by index into make([]int, n). The allocation counts tell the story — the nil-slice version re-allocates and copies over a dozen times, while the preallocated versions allocate exactly once. If you know the size up front (even approximately), tell the runtime.
1 CPU
32 CPUs
Allocates make([]int, sliceSize) and assigns elements by index. One allocation like the capacity variant, but also skips append's per-call length/capacity bookkeeping. The trade-off: the slice starts at full length, so a bug that skips an index silently leaves a zero value instead of a shorter slice.
Preallocates the backing array with make([]int, 0, sliceSize) and appends into it. The append calls never outgrow capacity, so there is exactly one allocation and zero copies — while keeping the convenient append API and correct length tracking.
Starts with a nil slice and lets append grow it. Each time capacity is exhausted the runtime allocates a larger backing array (roughly doubling for small slices, growing ~25% for large ones) and copies every element over. Building 10,000 elements this way triggers a whole series of allocations and copies.
Contributors