【发布时间】:2016-07-07 15:50:36
【问题描述】:
我在检查 GO 中的内存分配性能时偶然发现了一件有趣的事情。
package main
import (
"fmt"
"time"
)
func main(){
const alloc int = 65536
now := time.Now()
loop := 50000
for i := 0; i<loop;i++{
sl := make([]byte, alloc)
i += len(sl) * 0
}
elpased := time.Since(now)
fmt.Printf("took %s to allocate %d bytes %d times", elpased, alloc, loop)
}
我在 Core-i7 2600 上运行它,Go 版本 1.6 64 位(在 32 位上也有相同的结果)和 16GB 内存(在 WINDOWS 10 上) 因此,当 alloc 为 65536(正好是 64K)时,它会运行 30 秒(!!!!!!)。 当 alloc 为 65535 时,大约需要 200 毫秒。 有人可以向我解释一下吗? 我在家里用我的核心 i7-920 @ 3.8GHZ 尝试了相同的代码,但它没有显示相同的结果(都花了大约 200 毫秒)。有人知道发生了什么吗?
【问题讨论】:
-
要添加更多变化,在 Windows 7(Go 1.6,64 位)上尝试您的代码,无论
alloc是65536还是65535,我都会得到 17 秒。跨度> -
我不是分配内部的专家,但我只想提一下,分配一个 65536 字节的切片实际上是分配它加上 2 个整数(
len和cap计数器),所以实际上超过 64KB。 -
为了给问题添加更多信息,我在我的 Archlinux (i7-4720HQ @ 2.60GHz) 上运行了代码,它持续花费了大约 600 毫秒。您应该尝试在需要很长时间的设置上使用分析工具。如果您还不知道它实际上是开始学习它的好案例。
-
您可以尝试禁用垃圾收集器 (GOGC=off) 看看是否是问题所在。使用 16 GB 的 RAM,您应该有足够的内存。
-
是的。 set GOGC=off 确实提高了性能。所以我想我现在明白发生了什么。由于逃逸分析,golang 在堆上分配内存,然后 gc 需要清理它。当我分配少于 64K 时,go 使用堆栈。当数组在堆栈上时,它会自行清理,并且分配只需要一条 CPU 指令(只需创建一个指向堆栈上某处的指针)。
标签: performance memory go