Golang内存基准测试结果异常及内存吞吐量获取咨询
Go基准测试问题与解决方案
一、软硬件配置
goos: windows goarch: amd64 cpu: Intel(R) Core(TM) i7-8700 CPU @ 3.20GHz go version: go1.21.5 Available Memory: 64GB
二、执行的基准测试命令
go test -bench=MyCodeBench -benchtime=1x -timeout=120m -benchmem -run=^$
注:因代码执行耗时久,需设置120分钟超时,否则会触发
Test killed with quit: ran too long错误。
三、基准测试结果
MyCodeBench 1 776903113600 ns/op 402860098688 B/op 90982299 allocs/op
转换后显示402GB/op,但实际运行时任务管理器仅显示23GB内存占用——这里的B/op是基准测试期间累计内存分配总量,并非程序运行时的实时内存占用。
问题1:如何获取正确的基准测试结果?
要获取程序运行时的峰值内存占用(即当前内存使用量),可通过以下方式:
- 手动监控内存状态:在基准测试代码中使用
runtime.ReadMemStats()读取内存统计信息,关键字段说明:HeapAlloc:当前堆内存中已分配的对象大小(实时内存占用核心参考)HeapSys:程序从操作系统获取的总内存量HeapInuse:当前正在使用的堆内存页大小
示例代码:
import "runtime" func BenchmarkMyCodeBench(b *testing.B) { var memStats runtime.MemStats var peakAlloc uint64 // 测试前获取初始状态 runtime.ReadMemStats(&memStats) initialAlloc := memStats.HeapAlloc b.ResetTimer() for i := 0; i < b.N; i++ { MyCode() // 监控过程中的峰值内存 runtime.ReadMemStats(&memStats) currentAlloc := memStats.HeapAlloc - initialAlloc if currentAlloc > peakAlloc { peakAlloc = currentAlloc } } b.StopTimer() // 自定义输出峰值内存 b.ReportMetric(float64(peakAlloc)/1024/1024, "MB_peak") } - 使用pprof分析:添加内存 profiling 参数生成分析文件,再通过工具查看峰值:
执行完成后,运行go test -bench=MyCodeBench -benchtime=1x -timeout=120m -benchmem -run=^$ -memprofile=mem.profgo tool pprof mem.prof,在交互模式中输入top或web即可查看内存占用细节。
问题2:如何获取内存吞吐量(MB/s)?
调用SetBytes()未生效的常见原因是调用位置错误或传入参数不符合要求,正确实现步骤如下:
- 确定单次操作处理的字节数:比如你的代码处理了一段数据,计算这段数据的总字节数。
- 正确调用
SetBytes():需在基准测试函数的循环结束后调用,且确保在ResetTimer()之后执行测试逻辑,避免初始化时间干扰。
示例代码:
func BenchmarkMyCodeBench(b *testing.B) { // 初始化待处理数据(仅执行一次) inputData := []byte("your large data here") processedBytes := int64(len(inputData)) // 单次操作处理的字节数 b.ResetTimer() // 重置计时器,排除初始化耗时 for i := 0; i < b.N; i++ { YourProcessingFunction(inputData) // 执行测试代码 } b.SetBytes(processedBytes) // 设置单次操作的字节数,基准测试工具会自动计算MB/s }
- 验证输出:重新运行基准测试命令,结果中会新增
MB/s指标,计算公式为:(总处理字节数) / (总耗时秒数) / 1024 / 1024。若仍未显示,检查是否processedBytes为0,或b.N为0(但你设置了-benchtime=1x,b.N应为1)。
内容的提问来源于stack exchange,提问作者Okay
相关产品推荐
相关产品推荐

