我在检查 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 毫秒)。有人知道发生了什么事吗?
最佳答案
设置 GOGC=off 可提高性能(降至不到 100 毫秒)。为什么?
因为escape analysis .当您使用 go build -gcflags -m
构建时,编译器会打印逃逸到堆中的任何分配。这真的取决于你的机器和 GO 编译器版本,但是当编译器决定分配应该移动到堆时,它意味着两件事:
1.分配将花费更长的时间(因为在堆栈上“分配”只是 1 个 cpu 指令)
2. GC 稍后将不得不清理该内存 - 花费更多的 CPU 时间
对于我的机器,65536 字节的分配逃逸到堆中,而 65535 字节则没有。
这就是为什么 1 个字节将整个过程从 200 毫秒更改为 30 秒。太棒了..
关于performance - golang slice 分配性能,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36125927/