skip to content

What does runtime.MemProfileRate control in Go, and what is its default value?

level: middleimportance: nice to knowfreq 34%

answer

  1. a byte interval, not a percentage
  2. profiling is on by default
  3. half a megabyte
  4. samples are scaled back up
  5. one means record everything

basics

~10 s

It sets Go's memory-profile sampling rate: about one allocation is recorded per MemProfileRate bytes allocated, default 512 KB. Totals are scaled estimates. A rate of 1 records everything; 0 turns profiling off.

solid answer

~40 s

`runtime.MemProfileRate` is the memory profiler's sampling rate, expressed in bytes: the runtime aims to record one allocation for every `MemProfileRate` bytes allocated, and the default is 512 KB. Recorded samples are scaled back up so the profile estimates true totals, which is why the numbers are approximations rather than exact byte counts. Setting it to 1 records every allocation, which is what you want in a focused benchmark and never in production because of the CPU and memory cost; setting it to 0 disables memory profiling entirely. It should be set once, as early as possible — at the top of `main` or in an `init` — because changing it mid-run leaves you with a profile assembled under two different rates. `go test -memprofilerate=1` sets it for a single test or benchmark run.

code

go · 6 lines
go
func init() {
	// Default is 512 KB: one sampled allocation per 512 KB allocated.
	// 1 records every allocation - exact, and far slower.
	// 0 disables memory profiling entirely.
	runtime.MemProfileRate = 1
}

go deeper

for a junior

Remember one fact and one implication: Go samples memory allocations by default, so heap profile numbers are estimates rather than exact counts of every allocation.

for a middle

Be able to state the default of 512 KB per sample, explain that samples are scaled up to estimate totals, and say what 1 and 0 do to the rate.

for a senior

Show that you know which conclusions the sampling supports: big entries are real, tiny ones are noise, and rare small allocations may be missing entirely. Raise resolution in a benchmark, never in the live service.

for a principal

Treat always-on memory profiling as a deliberate standing cost the platform pays for permanent diagnosability, and be ready to defend leaving it at the default when someone proposes disabling it for throughput.

## The rate is a byte interval, not a percentage `runtime.MemProfileRate` is a plain `int` variable in the `runtime` package holding a number of bytes. The profiler's goal is to record roughly **one allocation for every `MemProfileRate` bytes allocated** across the whole program. Its default value is 512 KB (524288). So it is not "sample 1% of allocations" and not "sample every 512 KB *of one allocation site*". It is a global byte odometer: as your program allocates, every time it has passed roughly another `MemProfileRate` bytes, the allocation that trips the counter is recorded with its full call stack. ## Why sampled at all Recording every allocation with a stack trace would be ruinous. Go programs allocate constantly — every string concatenation, every append that grows, every interface box — and capturing a stack per allocation would dominate runtime and inflate the profile itself. Sampling at 512 KB makes memory profiling cheap enough to leave **on by default in every Go program**, which is why you can pull a heap profile from a production service that was not started in any special mode. That default-on property is the reason the rate is chosen the way it is. ## Scaling: why the numbers are estimates A sampled allocation stands in for the allocations the profiler did not record around it, so the runtime scales each sample up when it builds the profile. A stack that truly allocated 8 GB will report close to 8 GB even though only a few thousand allocations were captured. The consequence for reading a profile is that **large entries are trustworthy and small ones are noisy**. If one site shows 40 GB and another shows 12 GB, that ordering is real. If two sites show 512 KB and 1 MB, you may be looking at one and two sampled allocations, and the difference means nothing. Anything that allocates only a little, or allocates only on a rare path, may not appear at all. ## Turning the resolution up When you want exact attribution — typically in a benchmark that isolates one function — set the rate to 1: ```go func init() { runtime.MemProfileRate = 1 // record every allocation: benchmarks only } ``` or pass `go test -memprofilerate=1` for that run. Now every allocation is recorded, the counts are exact, and the program is much slower and holds far more profiling state. This is a measurement mode, not an operating mode. Setting it to 0 disables memory profiling. That saves a small amount of work but costs you the ability to diagnose a memory problem in that process at all, which is almost never a trade worth making in a service. ## Set it once, early The rate should be changed at most once, as early in execution as possible. If you flip it halfway through a run, the profile you eventually write is a mixture of records gathered under different scaling assumptions, and the totals are meaningless. Treat it as a startup decision, not a runtime knob. ## What it does not change It does not change what the profile measures, only how finely. The four sample indexes — live bytes, live objects, cumulative bytes, cumulative objects — are the same at any rate. It also does not affect CPU profiling, blocking or contention profiles; those have their own independent controls. ## Interview-shaped takeaways * Default 512 KB, expressed in bytes allocated per sample. * Numbers in a heap profile are **scaled estimates**; treat small entries with suspicion. * 1 = record everything (benchmarks), 0 = off. * Set once at startup. * Memory profiling is on by default in every Go program, which is why the rate matters: it is a permanent, low-grade tax that buys you always-available diagnosis.

  • A heap profile shows one allocation site at exactly 512 KB. How much should you trust it?
    Barely at all. At the default rate that is consistent with a single sampled allocation standing in for its interval, so the figure is one data point scaled up. Trust the ordering of large entries; to resolve small ones, re-measure in a benchmark with `runtime.MemProfileRate = 1` or `go test -memprofilerate=1`.
  • What breaks if you change runtime.MemProfileRate while the program is already running?
    The profile ends up mixing records captured under different scaling factors, so its totals no longer estimate anything coherent. The rate is meant to be set once, as early as possible — top of `main` or an `init` — and left alone.
  • Why is Go's memory profiler enabled by default when its CPU profiler is not?
    Because at one sample per 512 KB allocated the cost is small enough to carry permanently, and the payoff is that any process can be asked for a heap profile without a restart or a special build. CPU profiling installs periodic sampling with a much higher continuous cost, so it is started explicitly for a bounded window.

saying these in an interview costs you the question

  • Believes the profile counts every allocation exactly
  • Reads small profile entries as precise measurements
  • Ships MemProfileRate = 1 to production
  • Flips the rate repeatedly during a run
  • Thinks the rate is a percentage of allocations