Why this matters

The bug. A Go slice is (pointer, len, cap). data[:1] reuses the same pointer and the same backing array; only len and cap shrink. Whatever the caller does with the result, the original buffer can't be garbage-collected until that sub-slice is released too.

The fix. Allocate a fresh one-byte slice. []byte{data[0]}, append(nil, data[0]), or an explicit make + copy all break the reference; the big array becomes eligible for GC as soon as the caller's reference to it expires.

Heuristic. Whenever a long-lived slice points into a much larger one, copy. The classic offenders are HTTP middleware that retain r.URL.Path[:n], log shippers that keep header substrings, and parsers returning sub-tokens.

Review heuristic

Every long-lived collection (cache, registry, event bus, observer list) needs an eviction or unsubscribe path that fires deterministically. "It'll get GC'd" is true for the value but not for the reference holding it.

External reference: CWE-401: Missing Release of Memory after Effective Lifetime.

Go FAQ: 'Why does my program hold so much memory?'