You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Golang堆Profile与runtime.Memstats结果差异及可信度疑问

Go内存统计差异:HeapInuse、pprof与VmRSS

现象描述

我拿到的runtime.Memstats数据显示HeapInuse约为14.76GB:

# Alloc =15850481912
# TotalAlloc = 14112784178272
# SyS =27469378624
# Lookups =0
# Mallocs = 220246619671
# Frees = 220208758959
# HeapAlloc = 15850481912
# HeapSys = 26495549440
# HeapIdle = 10622779392
# HeapInuse = 15872770048
# HeapReleased = 586293248
# HeapObjects = 37860712
# Stack = 4063232 / 4063232
# MSpan = 42770560 /213057600
# Mcache = 9600 /15600
# BuckHashsys = 2771335
# GCsys =732745144
# Othersys = 21176273
# LastGc = 1695642639886128527

但用go tool pprof查看sample_index=inuse_space的堆Profile时,总在用空间仅约12616.97MB,和HeapInuse存在明显差异:

Showing nodes accounting for 12551.20MB, 99.48% of 12616.97MB total
Dropped 143 nodes (cum <= 63.08MB)
Showing top 10 nodes out of 14 
flat    flat%  sum%    cum     cum%
12288MB 97.39% 97.39% 12288MB 97.39% github.com/coocood/freecache.NewRingBuf (inline)
262.53MB 2.08% 99.47% 262.53MB 2.08% github.com/coocood/freecache.(*segment).expand (inline)
0.67MB 0.0053% 99.48% 12288.67MB 97.40% github.com/coocood/freecache.NewCacheCustomTimer

另外查看/proc/pid/stat的内存统计,VmRSS数值(约16.1GB)更接近HeapInuse:

VmPeak: 28930944 kB
VmSize: 28865408 kB
VmLck:         0 kB
VmPin:         0 kB
VmHWM : 16605472 kB
VmRSS : 16605472 kB
RssAnon:        16576956 kB
RssFile:           28504 kB
RssShmem:             12 kB
VmData: 27090500 kB
VmStk:       132 kB
VmExe:     28488 kB
VmLib:      4220 kB
VMPTE:     34552 kB
VmSwap:        0 kB

差异原因分析

1. Memstats.HeapInuse 与 pprof inuse_space

  • *HeapInuse*:统计的是Go堆管理器从操作系统申请的、至少包含一个存活对象的内存块(span)的总大小。它不仅包含用户程序实际使用的对象内存(对应HeapAlloc),还包括每个span内部的空闲碎片(比如一个8KB的span里只放了1KB对象,整个8KB都算入HeapInuse)。
  • *pprof inuse_space*:仅统计用户程序实际持有、正在使用的存活对象的内存大小,是HeapAlloc的近似值。但它存在局限性:
    • 无法追踪堆外内存(比如通过syscall.Mmap、cgo直接分配的内存);
    • 若某些内存使用了特殊的内存管理机制(如自定义内存池、unsafe.Pointer绕过GC追踪),可能被遗漏;
    • 采样或快照机制可能过滤掉小对象或合并节点(但你这里dropped的节点仅占63MB,不是主要差异来源)。
      你这里的差异大概率是因为freecache的部分内存未被pprof完全追踪,或是程序中存在其他未被pprof统计的存活对象。

2. Memstats.HeapInuse 与 /proc/pid/stat VmRSS

  • *VmRSS*:是进程实际占用的物理内存(驻留集大小),包含了所有进程使用的内存:Go堆(HeapInuse)、栈内存、程序代码、共享库、文件映射内存、cgo内存等。因此它的数值会比HeapInuse大,因为覆盖了非堆内存区域。你这里的差值(约1.3GB)正好对应栈、程序代码、共享库等非堆内存的总和,属于正常现象。

该信任哪个统计结果?

  • 若要了解Go堆管理器从OS获取的、正在使用的堆内存总量(含碎片),选Memstats.HeapInuse;
  • 若要分析用户程序中存活对象的内存分布,定位内存占用热点,选pprof inuse_space(注意排查堆外内存是否被遗漏);
  • 若要了解进程实际占用的物理内存总量,选/proc/pid/stat的VmRSS。

内容的提问来源于stack exchange,提问作者Jacky Zhao

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 16:09:50