【发布时间】:2019-05-27 07:34:03
【问题描述】:
我正在维护一个 Go 项目的代码,该项目读取和写入大量数据,并且已经成功完成了一段时间。最近,我做了一个更改:在程序开始时将一个包含大约 200 万条记录的 CSV 文件加载到一个带有结构值的映射中。此映射仅在 B 部分中使用,但首先在 A 部分中执行。第一部分的运行速度明显比以前慢(处理时间增加了四倍)。这很奇怪,因为那部分逻辑没有改变。 我花了一个星期试图解释这是怎么发生的。以下是我采取的步骤(提到性能时,我总是指A部分,其中不包括将数据加载到内存中的时间,实际上与它无关):
- 程序在 Docker 容器内的服务器上运行。但是我已经能够在没有容器的情况下在我的笔记本电脑上重现它:与我在内存中没有加载文件数据的情况下运行它相比,性能确实有所下降。
- 服务器有大量 RAM。尽管加载文件时显然会使用更多内存,但没有达到任何限制。我也没有看到内存使用和磁盘 I/O 出现峰值或其他奇怪的模式。对于这些检查,我使用了 pprof、htop 和 iotop。
- 当加载数据但地图设置为零时,性能再次正常。
- 将数据加载到切片而不是映射中可减少 x4 到 x2 的性能下降(但内存使用量与映射大致相同)。
- 这让我想知道是否可以在 A 部分的某个地方访问地图/切片,即使它不应该访问。映射存储在结构类型的字段中。我检查了一下,这个结构总是通过指针传递(包括所有 goroutines)。将其设为全局变量而不是指针字段并不能解决问题。
- 在标准库之外有一个依赖项。问题是图书馆引起的吗?它强制进行一些垃圾收集。禁用它并没有什么不同。我发现了另一个不相关的类似库,使用它作为替代可以提高性能,但加载文件数据时仍然需要更长的时间。
什么可能导致这种影响或者我该如何发现它?
【问题讨论】:
-
能否请您在图表的 X 和 Y 轴上添加标签
-
两个厘米。首先,您的问题具体是什么?您想知道如何跟踪内存泄漏吗?其次,你没有展示一个最小的例子或任何代码。所以很难猜测发生了什么
-
“
The server had a huge amount of RAM. Although obviously more memory is used when the file is loaded, no limits are hit”。 CPU缓存大小限制如何?例如。加载数据可能会导致所有其他数据被推出缓存(并且由于缓存未命中而使使用其他数据的代码变慢)。 -
用坐标轴上的标签和一个明确的问题更新了问题。
-
@Brendan 有趣,这是我没有想到的。但我不相信这是我遇到的。运行速度较慢的部分代码由文件读取和写入组成,不涉及任何先前的数据。
标签: performance go memory