Skip to content

Commit f67c9de

Browse files
committed
runtime: document MemStats
This documents all fields in MemStats and more clearly documents where mstats differs from MemStats. Fixes #15849. Change-Id: Ie09374bcdb3a5fdd2d25fe4bba836aaae92cb1dd Reviewed-on: https://go-review.googlesource.com/28972 Reviewed-by: Rob Pike <[email protected]> Reviewed-by: Hyang-Ah Hana Kim <[email protected]>
1 parent 2098e5d commit f67c9de

File tree

1 file changed

+288
-49
lines changed

1 file changed

+288
-49
lines changed

src/runtime/mstats.go

Lines changed: 288 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,13 @@ import (
1414

1515
// Statistics.
1616
// If you edit this structure, also edit type MemStats below.
17+
// Their layouts must match exactly.
18+
//
19+
// For detailed descriptions see the documentation for MemStats.
20+
// Fields that differ from MemStats are further documented here.
21+
//
22+
// Many of these fields are updated on the fly, while others are only
23+
// updated when updatememstats is called.
1724
type mstats struct {
1825
// General statistics.
1926
alloc uint64 // bytes allocated and not yet freed
@@ -24,18 +31,36 @@ type mstats struct {
2431
nfree uint64 // number of frees
2532

2633
// Statistics about malloc heap.
27-
// protected by mheap.lock
34+
// Protected by mheap.lock
35+
//
36+
// In mstats, heap_sys and heap_inuse includes stack memory,
37+
// while in MemStats stack memory is separated out from the
38+
// heap stats.
2839
heap_alloc uint64 // bytes allocated and not yet freed (same as alloc above)
29-
heap_sys uint64 // bytes obtained from system
40+
heap_sys uint64 // virtual address space obtained from system
3041
heap_idle uint64 // bytes in idle spans
3142
heap_inuse uint64 // bytes in non-idle spans
3243
heap_released uint64 // bytes released to the os
3344
heap_objects uint64 // total number of allocated objects
3445

46+
// TODO(austin): heap_released is both useless and inaccurate
47+
// in its current form. It's useless because, from the user's
48+
// and OS's perspectives, there's no difference between a page
49+
// that has not yet been faulted in and a page that has been
50+
// released back to the OS. We could fix this by considering
51+
// newly mapped spans to be "released". It's inaccurate
52+
// because when we split a large span for allocation, we
53+
// "unrelease" all pages in the large span and not just the
54+
// ones we split off for use. This is trickier to fix because
55+
// we currently don't know which pages of a span we've
56+
// released. We could fix it by separating "free" and
57+
// "released" spans, but then we have to allocate from runs of
58+
// free and released spans.
59+
3560
// Statistics about allocation of low-level fixed-size structures.
3661
// Protected by FixAlloc locks.
37-
stacks_inuse uint64 // this number is included in heap_inuse above
38-
stacks_sys uint64 // always 0 in mstats
62+
stacks_inuse uint64 // this number is included in heap_inuse above; differs from MemStats.StackInuse
63+
stacks_sys uint64 // only counts newosproc0 stack in mstats; differs from MemStats.StackSys
3964
mspan_inuse uint64 // mspan structures
4065
mspan_sys uint64
4166
mcache_inuse uint64 // mcache structures
@@ -64,7 +89,7 @@ type mstats struct {
6489
nfree uint64
6590
}
6691

67-
// Statistics below here are not exported to Go directly.
92+
// Statistics below here are not exported to MemStats directly.
6893

6994
tinyallocs uint64 // number of tiny allocations that didn't cause actual allocation; not exported to go directly
7095

@@ -118,58 +143,266 @@ var memstats mstats
118143
// A MemStats records statistics about the memory allocator.
119144
type MemStats struct {
120145
// General statistics.
121-
Alloc uint64 // bytes allocated and not yet freed
122-
TotalAlloc uint64 // bytes allocated (even if freed)
123-
Sys uint64 // bytes obtained from system (sum of XxxSys below)
124-
Lookups uint64 // number of pointer lookups
125-
Mallocs uint64 // number of mallocs
126-
Frees uint64 // number of frees
127-
128-
// Main allocation heap statistics.
129-
HeapAlloc uint64 // bytes allocated and not yet freed (same as Alloc above)
130-
HeapSys uint64 // bytes obtained from system
131-
HeapIdle uint64 // bytes in idle spans
132-
HeapInuse uint64 // bytes in non-idle span
133-
HeapReleased uint64 // bytes released to the OS
134-
HeapObjects uint64 // total number of allocated objects
135-
136-
// Low-level fixed-size structure allocator statistics.
137-
// Inuse is bytes used now.
138-
// Sys is bytes obtained from system.
139-
StackInuse uint64 // bytes used by stack allocator
140-
StackSys uint64
141-
MSpanInuse uint64 // mspan structures
142-
MSpanSys uint64
143-
MCacheInuse uint64 // mcache structures
144-
MCacheSys uint64
145-
BuckHashSys uint64 // profiling bucket hash table
146-
GCSys uint64 // GC metadata
147-
OtherSys uint64 // other system allocations
146+
147+
// Alloc is bytes of allocated heap objects.
148+
//
149+
// This is the same as HeapAlloc (see below).
150+
Alloc uint64
151+
152+
// TotalAlloc is cumulative bytes allocated for heap objects.
153+
//
154+
// TotalAlloc increases as heap objects are allocated, but
155+
// unlike Alloc and HeapAlloc, it does not decrease when
156+
// objects are freed.
157+
TotalAlloc uint64
158+
159+
// Sys is the total bytes of memory obtained from the OS.
160+
//
161+
// Sys is the sum of the XSys fields below. Sys measures the
162+
// virtual address space reserved by the Go runtime for the
163+
// heap, stacks, and other internal data structures. It's
164+
// likely that not all of the virtual address space is backed
165+
// by physical memory at any given moment, though in general
166+
// it all was at some point.
167+
Sys uint64
168+
169+
// Lookups is the number of pointer lookups performed by the
170+
// runtime.
171+
//
172+
// This is primarily useful for debugging runtime internals.
173+
Lookups uint64
174+
175+
// Mallocs is the cumulative count of heap objects allocated.
176+
Mallocs uint64
177+
178+
// Frees is the cumulative count of heap objects freed.
179+
Frees uint64
180+
181+
// Heap memory statistics.
182+
//
183+
// Interpreting the heap statistics requires some knowledge of
184+
// how Go organizes memory. Go divides the virtual address
185+
// space of the heap into "spans", which are contiguous
186+
// regions of memory 8K or larger. A span may be in one of
187+
// three states:
188+
//
189+
// An "idle" span contains no objects or other data. The
190+
// physical memory backing an idle span can be released back
191+
// to the OS (but the virtual address space never is), or it
192+
// can be converted into an "in use" or "stack" span.
193+
//
194+
// An "in use" span contains at least one heap object and may
195+
// have free space available to allocate more heap objects.
196+
//
197+
// A "stack" span is used for goroutine stacks. Stack spans
198+
// are not considered part of the heap. A span can change
199+
// between heap and stack memory; it is never used for both
200+
// simultaneously.
201+
202+
// HeapAlloc is bytes of allocated heap objects.
203+
//
204+
// "Allocated" heap objects include all reachable objects, as
205+
// well as unreachable objects that the garbage collector has
206+
// not yet freed. Specifically, HeapAlloc increases as heap
207+
// objects are allocated and decreases as the heap is swept
208+
// and unreachable objects are freed. Sweeping occurs
209+
// incrementally between GC cycles, so these two processes
210+
// occur simultaneously, and as a result HeapAlloc tends to
211+
// change smoothly (in contrast with the sawtooth that is
212+
// typical of stop-the-world garbage collectors).
213+
HeapAlloc uint64
214+
215+
// HeapSys is bytes of heap memory obtained from the OS.
216+
//
217+
// HeapSys measures the amount of virtual address space
218+
// reserved for the heap. This includes virtual address space
219+
// that has been reserved but not yet used, which consumes no
220+
// physical memory, but tends to be small, as well as virtual
221+
// address space for which the physical memory has been
222+
// returned to the OS after it became unused (see HeapReleased
223+
// for a measure of the latter).
224+
//
225+
// HeapSys estimates the largest size the heap has had.
226+
HeapSys uint64
227+
228+
// HeapIdle is bytes in idle (unused) spans.
229+
//
230+
// Idle spans have no objects in them. These spans could be
231+
// (and may already have been) returned to the OS, or they can
232+
// be reused for heap allocations, or they can be reused as
233+
// stack memory.
234+
//
235+
// HeapIdle minus HeapReleased estimates the amount of memory
236+
// that could be returned to the OS, but is being retained by
237+
// the runtime so it can grow the heap without requesting more
238+
// memory from the OS. If this difference is significantly
239+
// larger than the heap size, it indicates there was a recent
240+
// transient spike in live heap size.
241+
HeapIdle uint64
242+
243+
// HeapInuse is bytes in in-use spans.
244+
//
245+
// In-use spans have at least one object in them. These spans
246+
// can only be used for other objects of roughly the same
247+
// size.
248+
//
249+
// HeapInuse minus HeapAlloc esimates the amount of memory
250+
// that has been dedicated to particular size classes, but is
251+
// not currently being used. This is an upper bound on
252+
// fragmentation, but in general this memory can be reused
253+
// efficiently.
254+
HeapInuse uint64
255+
256+
// HeapReleased is bytes of physical memory returned to the OS.
257+
//
258+
// This counts heap memory from idle spans that was returned
259+
// to the OS and has not yet been reacquired for the heap.
260+
HeapReleased uint64
261+
262+
// HeapObjects is the number of allocated heap objects.
263+
//
264+
// Like HeapAlloc, this increases as objects are allocated and
265+
// decreases as the heap is swept and unreachable objects are
266+
// freed.
267+
HeapObjects uint64
268+
269+
// Stack memory statistics.
270+
//
271+
// Stacks are not considered part of the heap, but the runtime
272+
// can reuse a span of heap memory for stack memory, and
273+
// vice-versa.
274+
275+
// StackInuse is bytes in stack spans.
276+
//
277+
// In-use stack spans have at least one stack in them. These
278+
// spans can only be used for other stacks of the same size.
279+
//
280+
// There is no StackIdle because unused stack spans are
281+
// returned to the heap (and hence counted toward HeapIdle).
282+
StackInuse uint64
283+
284+
// StackSys is bytes of stack memory obtained from the OS.
285+
//
286+
// StackSys is StackInuse, plus any memory obtained directly
287+
// from the OS for OS thread stacks (which should be minimal).
288+
StackSys uint64
289+
290+
// Off-heap memory statistics.
291+
//
292+
// The following statistics measure runtime-internal
293+
// structures that are not allocated from heap memory (usually
294+
// because they are part of implementing the heap). Unlike
295+
// heap or stack memory, any memory allocated to these
296+
// structures is dedicated to these structures.
297+
//
298+
// These are primarily useful for debugging runtime memory
299+
// overheads.
300+
301+
// MSpanInuse is bytes of allocated mspan structures.
302+
MSpanInuse uint64
303+
304+
// MSpanSys is bytes of memory obtained from the OS for mspan
305+
// structures.
306+
MSpanSys uint64
307+
308+
// MCacheInuse is bytes of allocated mcache structures.
309+
MCacheInuse uint64
310+
311+
// MCacheSys is bytes of memory obtained from the OS for
312+
// mcache structures.
313+
MCacheSys uint64
314+
315+
// BuckHashSys is bytes of memory in profiling bucket hash tables.
316+
BuckHashSys uint64
317+
318+
// GCSys is bytes of memory in garbage collection metadata.
319+
GCSys uint64
320+
321+
// OtherSys is bytes of memory in miscellaneous off-heap
322+
// runtime allocations.
323+
OtherSys uint64
148324

149325
// Garbage collector statistics.
150-
NextGC uint64 // next collection will happen when HeapAlloc ≥ this amount
151-
LastGC uint64 // end time of last collection (nanoseconds since 1970)
152-
PauseTotalNs uint64
153-
PauseNs [256]uint64 // circular buffer of recent GC pause durations, most recent at [(NumGC+255)%256]
154-
PauseEnd [256]uint64 // circular buffer of recent GC pause end times
155-
NumGC uint32
156-
GCCPUFraction float64 // fraction of CPU time used by GC
157-
EnableGC bool
158-
DebugGC bool
159-
160-
// Per-size allocation statistics.
161-
// 61 is NumSizeClasses in the C code.
326+
327+
// NextGC is the target heap size of the next GC cycle.
328+
//
329+
// The garbage collector's goal is to keep HeapAlloc ≤ NextGC.
330+
// At the end of each GC cycle, the target for the next cycle
331+
// is computed based on the amount of reachable data and the
332+
// value of GOGC.
333+
NextGC uint64
334+
335+
// LastGC is the time the last garbage collection finished, as
336+
// nanoseconds since 1970 (the UNIX epoch).
337+
LastGC uint64
338+
339+
// PauseTotalNs is the cumulative nanoseconds in GC
340+
// stop-the-world pauses since the program started.
341+
//
342+
// During a stop-the-world pause, all goroutines are paused
343+
// and only the garbage collector can run.
344+
PauseTotalNs uint64
345+
346+
// PauseNs is a circular buffer of recent GC stop-the-world
347+
// pause times in nanoseconds.
348+
//
349+
// The most recent pause is at PauseNs[(NumGC+255)%256]. In
350+
// general, PauseNs[N%256] records the time paused in the most
351+
// recent N%256th GC cycle. There may be multiple pauses per
352+
// GC cycle; this is the sum of all pauses during a cycle.
353+
PauseNs [256]uint64
354+
355+
// PauseEnd is a circular buffer of recent GC pause end times,
356+
// as nanoseconds since 1970 (the UNIX epoch).
357+
//
358+
// This buffer is filled the same way as PauseNs. There may be
359+
// multiple pauses per GC cycle; this records the end of the
360+
// last pause in a cycle.
361+
PauseEnd [256]uint64
362+
363+
// NumGC is the number of completed GC cycles.
364+
NumGC uint32
365+
366+
// GCCPUFraction is the fraction of this program's available
367+
// CPU time used by the GC since the program started.
368+
//
369+
// GCCPUFraction is expressed as a number between 0 and 1,
370+
// where 0 means GC has consumed none of this program's CPU. A
371+
// program's available CPU time is defined as the integral of
372+
// GOMAXPROCS since the program started. That is, if
373+
// GOMAXPROCS is 2 and a program has been running for 10
374+
// seconds, its "available CPU" is 20 seconds. GCCPUFraction
375+
// does not include CPU time used for write barrier activity.
376+
//
377+
// This is the same as the fraction of CPU reported by
378+
// GODEBUG=gctrace=1.
379+
GCCPUFraction float64
380+
381+
// EnableGC indicates that GC is enabled. It is always true,
382+
// even if GOGC=off.
383+
EnableGC bool
384+
385+
// DebugGC is currently unused.
386+
DebugGC bool
387+
388+
// BySize reports per-size class allocation statistics.
389+
//
390+
// BySize[N] gives statistics for allocations of size S where
391+
// BySize[N-1].Size < S ≤ BySize[N].Size.
392+
//
393+
// This does not report allocations larger than BySize[60].Size.
162394
BySize [61]struct {
163395
Size uint32
164396
Mallocs uint64
165397
Frees uint64
166398
}
167399
}
168400

169-
// Size of the trailing by_size array differs between Go and C,
401+
// Size of the trailing by_size array differs between mstats and MemStats,
170402
// and all data after by_size is local to runtime, not exported.
171-
// NumSizeClasses was changed, but we cannot change Go struct because of backward compatibility.
172-
// sizeof_C_MStats is what C thinks about size of Go struct.
403+
// NumSizeClasses was changed, but we cannot change MemStats because of backward compatibility.
404+
// sizeof_C_MStats is the size of the prefix of mstats that
405+
// corresponds to MemStats. It should match Sizeof(MemStats{}).
173406
var sizeof_C_MStats = unsafe.Offsetof(memstats.by_size) + 61*unsafe.Sizeof(memstats.by_size[0])
174407

175408
func init() {
@@ -181,6 +414,11 @@ func init() {
181414
}
182415

183416
// ReadMemStats populates m with memory allocator statistics.
417+
//
418+
// The returned memory allocator statistics are up to date as of the
419+
// call to ReadMemStats. This is in contrast with a heap profile,
420+
// which is a snapshot as of the most recently completed garbage
421+
// collection cycle.
184422
func ReadMemStats(m *MemStats) {
185423
stopTheWorld("read mem stats")
186424

@@ -194,8 +432,9 @@ func ReadMemStats(m *MemStats) {
194432
func readmemstats_m(stats *MemStats) {
195433
updatememstats(nil)
196434

197-
// Size of the trailing by_size array differs between Go and C,
198-
// NumSizeClasses was changed, but we cannot change Go struct because of backward compatibility.
435+
// The size of the trailing by_size array differs between
436+
// mstats and MemStats. NumSizeClasses was changed, but we
437+
// cannot change MemStats because of backward compatibility.
199438
memmove(unsafe.Pointer(stats), unsafe.Pointer(&memstats), sizeof_C_MStats)
200439

201440
// Stack numbers are part of the heap numbers, separate those out for user consumption

0 commit comments

Comments
 (0)