Start with a hypothesis-driven, reproducible process: detect → reproduce → isolate → fix → validate.1) Detect & gather signals- Alerts/metrics: RSS, heap_used, GC pause, fd count, CPU, OOM events (Prometheus/Grafana).- Correlate with deploys, traffic spikes, or config changes.2) Reproduce locally- Create a deterministic load test that mimics production traffic (wrk, vegeta, k6) and use same config, heap limits, and versions.- If leak is slow, accelerate by increasing load or decreasing GC thresholds.Example:bash
k6 run -e TARGET=http://localhost:8080 script.js
3) Tools to capture memory state- For JVM: jmap -dump:live,file=heap.hprof PID; jhat or Eclipse MAT to analyze dominators.- For Go: runtime/pprof; HTTP /debug/pprof/heap endpoint; collect with:bash
go tool pprof -http=:8081 binary heap.prof
- For native/C++: gcore to capture core, then use lldb/gdb + heap profiler (valgrind --tool=memcheck or massif) or jemalloc/TCMalloc stats.- Containerized: docker exec + nsenter, or use crictl; ensure you capture cgroup metrics and limit-aware RSS.4) Narrow down suspect code- Compare heap snapshots over time; diff HPROF/pprof outputs to see growth by allocation stack, type, or allocation site.- Look for: - Large retaining dominators or increasing populations of a type - Long-lived object graphs (caches, static maps, goroutine stacks) - File/socket/connection leaks (fd growth)- Add targeted logging/metrics and feature flags to disable suspected paths. Use binary search: disable half of features to see if leak persists.5) Fix & regression-proof- Implement fix (weak refs, explicit close, cache eviction, object pooling, minimize retention).- Add unit/integration tests that assert memory bounds under load (CI soak tests).- Add alerts (rate of heap growth, unusual GC frequency) and expose diagnostic endpoints.6) Validate in staging and production- Staging: run long-duration soak under realistic load + automated heap snapshots and compare to baseline.- Gradual rollout: canary with increased observability and roll-back plan.- Production: monitor memory slope, GC metrics, fd count, latency; capture post-deploy heap snapshot if anomaly reappears. Use retrospective heap diffs to confirm fix.Example specific commands:bash
# JVM
jmap -dump:live,file=heap.hprof $PID
# Go
curl -sS localhost:6060/debug/pprof/heap > heap.prof
go tool pprof -text ./binary heap.prof
Key validation criteria: memory usage stabilizes under steady-state load, GC behavior normalizes, no fd/goroutine leaks, and SLOs remain met.