Go Heap Profiles to Gain Complete Memory View via New memory_space Sample Type

A Go proposal (#79179) provisionally accepted to add a memory_space sample type to heap/alloc profiles, providing a full memory hierarchy from RSS down to live/dead heap, stacks, runtime, and non-Go memory, solving the long-standing gap where heap profiles show only about 50% of actual RSS.

TonyBai
TonyBai
TonyBai
Go Heap Profiles to Gain Complete Memory View via New memory_space Sample Type

Go developers frequently encounter a puzzling discrepancy: container RSS shows 2 GB, but pprof.Lookup("heap") reports less than 1 GB. The missing memory consists of dead heap (objects pending GC), goroutine stacks, runtime metadata (mspan, mcache), executable mappings, shared libraries, mmap regions, and cgo allocations — none of which appear in the default inuse_space heap profile.

The article outlines the three existing memory diagnostics: process RSS (OS physical memory), runtime/metrics (fine-grained runtime counters), and heap profile ( inuse_space live heap snapshot). Under default GOGC=100, live heap typically covers under 50% of actual Go memory usage because dead heap accumulates until the next GC cycle.

Proposal #79179 by Felix Geisendörfer, recently marked "active" and provisionally accepted, introduces a new memory_space sample type added to the existing heap and alloc profiles rather than creating a separate profile. This design maximizes discoverability (users see the enhanced view automatically) and avoids breaking continuous profiling pipelines that ignore default_sample_type.

Memory Hierarchy

The memory_space sample type presents a tree rooted at RSS (when available and ≥ Go Memory):

RSS → Go Memory / Non-Go Memory (computed as RSS − Go Memory)

Go Memory splits into Heap (Live / Dead), Stack , and Runtime (mspan, mcache, etc.)

If RSS is unavailable or Go Memory > RSS (e.g., due to reserved virtual memory), the profile falls back to showing only Go Memory and emits explicit warning frames:

[WARNING: RSS not supported on GOOS=X]
[WARNING: Go Memory (X MiB) > RSS (Y MiB)]

Key Design Decisions

Dead heap is valuable : In request-oriented services, short-lived allocations appear in both live and dead heap depending on GC timing; optimizing dead heap reduces overall memory pressure and enables more aggressive GOGC / GOMEMLIMIT settings.

Consistent snapshot at mark termination : The prototype captures a consistent runtime metrics snapshot aligned with live/dead heap stack traces. STW impact is minimal; RSS is read after mark termination to avoid syscalls during STW.

Profile size increase : Uncompressed size grows ~30%, compressed ~10% because pprof requires all samples to carry every sample type (zero-filled where absent). An opt-out via GOEXPERIMENT or GODEBUG is discussed; long-term relief is expected from the Recorder proposal (#74545).

Community Review Highlights

Positive reception: Austin Clements confirmed it solves long-standing heap profile confusion.

Data segment inclusion: On Linux, private writable file mappings are included in RSS via /proc/self/statm.

Virtual vs. physical memory: The warning-frame approach acknowledges the semantic gap rather than pretending equivalence.

Naming debate: Initially "rss", changed to "memory" to align with Kubernetes ( resources.limits.memory), cgroup v2 ( memory.current), Docker ( MemUsage), and Prometheus ( container_memory_working_set_bytes) terminology, and to match Go's own /memory/classes/... metrics.

Impact on Developers

Eliminates manual reconciliation of RSS, runtime/metrics, and heap profile.

A single pprof.Lookup("heap").WriteTo(f, 0) yields a complete attribution chain from RSS to call stacks.

Container cost optimization and incident response can directly see non-Go memory proportions in flame graphs.

Continuous profiling platforms must evaluate storage/transfer overhead from larger profiles.

The proposal remains in "provisionally accepted pending implementation" status; the review committee requests a production-quality implementation before final acceptance. Track progress at issue #79179.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

observabilityGopprofruntimememory profilingmemory_spaceproposalheap profile
TonyBai
Written by

TonyBai

Tony Bai's tech world (tonybai.com). Not satisfied with just "knowing how", we strive for mastery. Focused on Go language internals, high-quality engineering practices, and cloud‑native architecture, exploring cutting‑edge intersections of Go and AI. Gophers who pursue technology are welcome—follow me and evolve with Go.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.