Go

What does this print, and what memory problem does it illustrate?

Question 358MediumGo 1.22 to 1.25
func header(data []byte) []byte {
    return data[:4]
}

func main() {
    big := make([]byte, 10<<20) // 10 MiB
    h := header(big)
    big = nil
    runtime.GC()
    fmt.Println(len(h), cap(h))
}

Output: 4 10485760. The 4-byte slice still refers to the entire 10 MiB backing array, so none of it can be freed. The GC keeps whole allocations alive, not parts of them. This is the "sub-slice retention" leak, and it often happens when parsing a header or a few IDs out of large network buffers and storing them in a long-lived map.

The same applies to substrings: s[:10] of a 1 MB string keeps the whole 1 MB alive.

// Fixes: copy the small part out
func headerFixed(data []byte) []byte {
    return bytes.Clone(data[:4])   // or: append([]byte(nil), data[:4]...)
}

func idFromLine(line string) string {
    return strings.Clone(line[:8]) // Go 1.20+
}

Gotcha: the full slice expression data[:4:4] limits the capacity, so appends to the result cannot overwrite data, but it does not free the rest of the array. You need an actual copy. Use pprof's inuse_space to find where the retained memory was allocated.

More on Memory, GC & Runtime Internals

All 38 Memory, GC & Runtime Internals questions