Go Wiki: 編譯器與執行時最佳化
此頁面列出了編譯器進行的最佳化。請注意,這些最佳化不一定由語言規範保證。
介面值
介面值中的零寬度型別
將零寬度型別放入介面值中不會進行分配。
- gc 1.0+
- gccgo ?
介面值中的字長大小值
將字長大小或更小且非指標的型別放入介面值中不會進行分配。
- gc: 1.0-1.3,但不在 1.4+ 中
- gccgo: 從未
string 和 []byte
透過 []byte 進行 map 查詢
對於型別為 map[string]T 的 map m 和 []byte b,m[string(b)] 不會進行分配。(不會建立位元組切片的臨時字串副本)
- gc 1.4+
- gccgo ?
對 []byte(s) 進行 range
在將 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 呼叫。 Issue 和 commit。
- gc 1.5+
- gccgo ?
不可掃描物件
當元素型別不包含指標時(對於 map,鍵和值都不包含),垃圾回收器不會掃描切片、通道和 map 的底層緩衝區。這使得可以在記憶體中儲存大量資料集,而不會在垃圾回收時付出高昂代價。例如,以下 map 對 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 的一部分。