Go Wiki:编译器和运行时优化
此页面列出了编译器进行的优化。请注意,语言规范不保证这些优化。
接口值
接口值中的零宽度类型
在接口值中放置零宽度类型不会分配。
- gc 1.0+
- gccgo ?
接口值中的字大小值
在接口值中放置字大小或更小的非指针类型不会分配。
- gc:1.0-1.3,但不在 1.4+ 中
- gccgo:从不
string
和 []byte
通过 []byte
进行映射查找
对于类型为 map[string]T
的映射 m
和 []byte b
,m[string(b)]
不会分配。(不会创建字节切片的临时字符串副本)
- gc 1.4+
- gccgo ?
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
- gc: 1.5+(CL 3790)
- gccgo ?
逃逸分析和内联
使用 -gcflags -m
观察 gc 工具链的逃逸分析和内联决策结果。
(待办事项:解释 -gcflags -m
的输出)。
逃逸分析
Gc 编译器跨函数和包边界执行全局逃逸分析。但是,在很多情况下它会放弃。例如,分配给任何间接引用的内容(*p = ...
)都被视为已逃逸。其他可能抑制分析的内容包括:函数调用、包边界、切片字面量、子切片和索引等。完整的规则过于复杂,无法描述,因此请查看 -m
输出。
- gc 1.0+
- gccgo 8.0+.
函数内联
只有简短且简单的函数会被内联。要内联,函数必须符合以下规则
- 函数应足够简单,AST 节点数必须小于预算(80);
- 函数不包含诸如闭包、defer、recover、select 等复杂内容;
- 函数没有 go:noinline 前缀;
- 函数没有 go:uintptrescapes 前缀,因为在内联期间逃逸信息将丢失;
- 函数有主体;
- 等。
- gc 1.0+
- gccgo: -O1 及更高版本。
惯用法
优化后的 memclr
对于切片或数组 s,形式为
for i := range s {
s[i] = <zero value for element of s>
}
的循环被转换为高效的运行时 memclr 调用。问题和提交。
- gc 1.5+
- gccgo ?
不可扫描的对象
当元素类型不包含指针(对于映射,既包括键,也包括值)时,垃圾收集器不会扫描切片、通道和映射的底层缓冲区。这允许在内存中保存大型数据集,而无需在垃圾收集期间付出高昂的代价。例如,以下映射不会明显影响 GC 时间
type Key [64]byte // SHA-512 hash
type Value struct {
Name [32]byte
Balance uint64
Timestamp int64
}
m := make(map[Key]Value, 1e8)
- gc 1.5+
- gccgo ?
此内容是 Go Wiki 的一部分。