Golang / Golang Internals and Memory Management Interview Questions
What are the most common memory leak patterns in Go and how do you diagnose them?
Go's GC handles most memory management, but certain patterns prevent objects from being collected even when they are logically no longer needed:
| Pattern | Cause | Fix |
|---|---|---|
| Goroutine leak | Goroutine blocked forever on channel/I/O | Use context cancellation or close channels |
| Slice sub-slice holding large backing array | Small sub-slice keeps 100 MB backing array alive | Copy sub-slice: copy(small, big[start:end]) |
| Global variable accumulation | Global map or slice grown indefinitely | Add eviction, use expiring cache, or bounded data structure |
| Finalizer keeping object alive | Objects with finalizers are delayed one GC cycle | Avoid finalizers; use Cleaner or defer with explicit close |
| String conversion retaining bytes | []byte → string keeps original byte array | Use string(bytes) to copy; beware zero-copy hacks |
| time.Ticker not stopped | Ticker goroutine and channel alive until GC | Always call ticker.Stop() and drain the channel |
// Slice leak â sub-slice keeps large backing array alive func getHeader(data []byte) []byte { return data[:8] // BAD: keeps all of data alive } func getHeaderFixed(data []byte) []byte { header := make([]byte, 8) copy(header, data) // GOOD: independent small slice return header } // Ticker leak â always stop ticker := time.NewTicker(1 * time.Second) defer ticker.Stop() // MUST stop to avoid goroutine+channel leak for { select { case <-ticker.C: doWork() case <-ctx.Done(): return } } // Diagnosing memory leaks // 1. Monitor heap via /debug/pprof/heap // 2. Compare two heap snapshots over time: // go tool pprof -base old.pprof new.pprof // 3. Watch runtime.ReadMemStats â if HeapAlloc keeps growing // after GC, something is holding references // 4. goroutine profile: /debug/pprof/goroutine?debug=1 // if NumGoroutine keeps growing, you have goroutine leaks
More Related questions...