Go Wiki:编译器和运行时优化

此页面列出了编译器进行的优化。请注意,语言规范不保证这些优化。

接口值

接口值中的零宽度类型

在接口值中放置零宽度类型不会分配。

接口值中的字大小值

在接口值中放置字大小或更小的非指针类型不会分配。

string[]byte

通过 []byte 进行映射查找

对于类型为 map[string]T 的映射 m[]byte bm[string(b)] 不会分配。(不会创建字节切片的临时字符串副本)

range 遍历 []byte

string 转换为 []byte 以遍历字节时不分配内存

s := "foo"
for i, c := range []byte(s) {
    // ...
}

字符串比较转换

[]byte 转换为 string 以进行比较时不分配内存

var b1 string
var b2 []byte
var x = string(b1) == string(b2) // memeq
var y = string(b1) < string(b2)  // lexicographical comparison

逃逸分析和内联

使用 -gcflags -m 观察 gc 工具链的逃逸分析和内联决策结果。

(待办事项:解释 -gcflags -m 的输出)。

逃逸分析

Gc 编译器跨函数和包边界执行全局逃逸分析。但是,在很多情况下它会放弃。例如,分配给任何间接引用的内容(*p = ...)都被视为已逃逸。其他可能抑制分析的内容包括:函数调用、包边界、切片字面量、子切片和索引等。完整的规则过于复杂,无法描述,因此请查看 -m 输出。

函数内联

只有简短且简单的函数会被内联。要内联,函数必须符合以下规则

惯用法

优化后的 memclr

对于切片或数组 s,形式为

for i := range s {
    s[i] = <zero value for element of s>
}

的循环被转换为高效的运行时 memclr 调用。问题提交

不可扫描的对象

当元素类型不包含指针(对于映射,既包括键,也包括值)时,垃圾收集器不会扫描切片、通道和映射的底层缓冲区。这允许在内存中保存大型数据集,而无需在垃圾收集期间付出高昂的代价。例如,以下映射不会明显影响 GC 时间

type Key [64]byte // SHA-512 hash
type Value struct {
    Name      [32]byte
    Balance   uint64
    Timestamp int64
}
m := make(map[Key]Value, 1e8)

此内容是 Go Wiki 的一部分。