Runtime Environment: Socket, Container, Stack, Heap, cgo
GOMEMLIMIT governs the Go heap. It can't reach the browser sidecar, and it can't see cgo's malloc. Where your code actually runs matters.
GOMEMLIMITgoverns the Go heap. It can’t reach the browser sidecar, and it can’t see cgo’s malloc.
Where Your Code Actually Runs
- Socket = one end of a network conversation (IP + port); TCP connection = the open pipe between two sockets. HTTP keep-alive reuses the same pipe, which pins retries under L4 load balancing (Keep-Alive Pins Retries).
- L4 picks a destination once at connection time; L7 re-picks per request. K8s Service defaults to L4.
- Container = app + deps, isolated via cgroup for CPU/memory. Sidecar = a second container in the same pod; shared lifecycle, but separate process and memory.
- Stack = per-goroutine scratch space, auto-freed on return. Heap = data that outlives the function, reclaimed by GC.
GOMEMLIMITonly governs the heap. - cgo / off-heap = Go calling a C library (for example, libvips). The C side’s
mallocmemory is completely invisible to the Go runtime.GOMEMLIMITandGOMAXPROCScan’t touch it.
Role in This OOM
The browser sidecar is another process in the same pod (OS Vocabulary: Process to Syscall), with its own 2Gi memory ceiling. The Go heap was only 256Mi; GOMEMLIMIT was set on the Go process; it couldn’t touch the browser’s memory at all (Wrong Fix: GOMEMLIMIT and Git Archeology).
Same pod doesn’t mean same memory. A sidecar has its own ceiling and its own way to die.
References:
- https://beej.us/guide/bgnet/
- https://en.wikipedia.org/wiki/OSI_model
- https://kubernetes.io/docs/concepts/workloads/pods/
- https://pages.cs.wisc.edu/~remzi/OSTEP/
- https://pkg.go.dev/cmd/cgo
- https://go.dev/doc/gc-guide
Related: see OS Vocabulary: Process to Syscall for the process/thread boundary, GOMAXPROCS Caps Parallelism, Not Concurrency for why cpu:1 doesn’t limit I/O-bound work, or go back to the series overview.