runtime: implement MemStats.NumGC

Reading runtime.MemStats.NumGC is common enough in dependency code that its
absence is a compile error for programs that never look at the value. Rather
than add the field as a constant zero, track it:

- gc_blocks: count completed cycles in runGC, so collections triggered by an
  allocation are counted as well as explicit runtime.GC() calls. The counter is
  read and written under gcLock, like the other counters beside it.
- gc_boehm: report bdwgc's own gc_no from the prof_stats struct.
- gc_leaking: always 0, since that collector never completes a cycle.
This commit is contained in:
Moses Narrow
2026-08-13 20:26:19 -05:00
committed by Damian Gryski
parent d74f70bdd0
commit 338af91ae6
5 changed files with 19 additions and 3 deletions
+9
View File
@@ -56,6 +56,7 @@ var (
endBlock gcBlock // the block just past the end of the available space
gcTotalAlloc uint64 // total number of bytes allocated
gcMallocs uint64 // total number of allocations
gcNumGC uint32 // total number of completed collection cycles
gcLock task.PMutex // lock to avoid race conditions on multicore systems
)
@@ -610,6 +611,11 @@ func runGC() (freeBytes uintptr) {
dumpHeap()
}
// The cycle is complete. Counted here rather than in GC() so that
// collections triggered by an allocation are counted too. Every caller
// holds gcLock, the same lock ReadMemStats reads it under.
gcNumGC++
return
}
@@ -850,6 +856,9 @@ func ReadMemStats(m *MemStats) {
// Record the total allocated bytes.
m.TotalAlloc = gcTotalAlloc
// Record the number of completed collection cycles.
m.NumGC = gcNumGC
gcLock.Unlock()
}