为了账号安全,请及时绑定邮箱和手机立即绑定

为什么我的 Go 程序的内存波动这么大?

为什么我的 Go 程序的内存波动这么大?

Go
江户川乱折腾 2021-07-14 13:04:00
我有一个分配大量地图和切片的 Go 程序。通常有很多使用、分配开销等。我运行它,它加载了大量数据,然后我使用 Web 服务查询它。在我让它运行后,当它读入所有数据并且没有做任何查询(即应该是稳定的)时,我看到内存波动。最近有报道称:5.42 GB、5.01 GB 和 4.3 GB 的实内存。这是一个巨大的波动。我有大约 1.5 亿个对象(挂在主哈希表上的切片)。这是很多小物件。我预计会有一点波动(尽管当没有分配新对象并且主线程阻塞在套接字上时,我永远不会期望内存会增加)。可能的解释是大量小分配的开销只会乘以任何自然波动一些代码正在分配对象(虽然我看不到如何)Go GC 正在执行自己的分页 (?)我正在使用 Mac OS,但不知何故它有问题这种波动量是否正常/预期?
查看完整描述

2 回答

?
RISEBY

TA贡献1856条经验 获得超5个赞

波动可能是由于您的程序正在创建垃圾收集器最终必须收集的垃圾量。波动的频率将取决于您创建垃圾的数量/频率以及垃圾收集器收集它的时间。

一个变量是分配给栈还是堆是由编译器决定的。通常可以将指针、映射和切片分配给堆,但这只有在编译器的转义分析确定变量转义时才会发生。分配给堆的任何内容都需要进行垃圾回收。

即使 Go 处理堆栈与堆的细节,尽可能少地创建垃圾也会有很大的好处。您可以阅读垃圾收集器暂停 10 秒的极端情况。Go 垃圾收集器并不完美,但它正在改进。它改善得越多,你就越不必担心它。但你至少应该意识到这一点。

您可以运行以下命令来确定编译器将分配给堆的内容:

go build -gcflags=-m program.go

您可能会对实际分配给堆的内容感到惊讶。例如,即使您在本地使用 bytes.Buffer 它仍然会分配给堆,因为bytes.Buffer.buf 被重新切片。不管这是否应该发生,在某些情况下,您可能认为自己没有制造任何垃圾,但实际上确实如此。


查看完整回答
反对 回复 2021-07-19
  • 2 回答
  • 0 关注
  • 286 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信