Go 如何在 make 或 new 调用中分配内存?

How does Go allocate memory in make or new calls?

当我使用 make 或 new 调用创建新的切片或结构时:

s := make([]int64, 10, 100)
o := new(MyStruct)

Go 通过内存分配系统调用分配了多少内存?它是否预先分配内存,以便后续调用不会触发新的系统调用?

我问这个是因为我需要在我的代码中频繁分配内存。我不确定我是否需要自己实现一个内存分配器,或者我是否可以依赖 Go 来完成这些肮脏的工作。如果 Go 确实预分配内存,我可以自定义分配的块大小吗?

我在Go中写了一些实验代码,运行strace下的代码,但我不明白Go对mmap系统调用做了什么:

mmap(0xc000000000, 65536, PROT_NONE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xc000000000
munmap(0xc000000000, 65536)             = 0
mmap(NULL, 262144, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7efdd1017000
mmap(0xc208000000, 1048576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xc208000000
mmap(0xc207ff0000, 65536, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xc207ff0000
mmap(0xc000000000, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xc000000000
mmap(NULL, 65536, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7efdd1007000
mmap(NULL, 1439992, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7efdd0ea7000

您可能患有 "premature optimization" 综合症。语言规范没有说明make()分配的内存将如何分配。

例如,符合规范的 Go 实现可能会对执行 make([]foo, ...) 的函数进行彻底分析并证明:

  1. 返回的切片值没有超出函数范围。
  2. append() 未在此切片值上调用。
  3. 它没有传递给任何被调用函数的切片值。

在这种情况下,切片的后备存储可能就在堆栈上分配。

当然,我在夸大其词,但同样,语言规范中并未声明其语义。目前有两个成熟的 Go 实现(一个起源于 Google,被称为 gc,和 gccgo)还有更多的实现(llvmgo 似乎有很好的机会不负众望),各有特色

所以请考虑阅读 pprof 和一般的 Go 分析,并分析示例(但真实的)代码。

搜索 the mailing list 词 "profile"、"profiling"、"heap AND profile"、"CPU AND profile" 和 "pprof" 将提供很多关于它的见解给你。

还要考虑 this and this