はじめに
下記のページの「Quick look at some compiler’s optimizations」の翻訳のようなものです。そもそも下記のページを見つけるのに結構苦労した&日本語情報があまりなかったのでメモ。
最適化の結果を確認する
-
go build
やgo test
の際に-gcflags=-m
をつけると下記のように最適化結果が出力される
$ go build -gcflags=-m t.go
# command-line-arguments
./t.go:15: can inline NewUser
./t.go:21: inlining call to NewUser
./t.go:10: leaking param: u
./t.go:10: leaking param: u
./t.go:12: (*User).Greetings ... argument does not escape
./t.go:15: leaking param: name
./t.go:15: leaking param: location
./t.go:17: &User literal escapes to heap
./t.go:15: leaking param: name
./t.go:15: leaking param: location
./t.go:21: &User literal escapes to heap
./t.go:22: main ... argument does not escape
ちなみに t.go
はこんな感じ
package main
import "fmt"
type User struct {
Id int
Name, Location string
}
func (u *User) Greetings() string {
return fmt.Sprintf("Hi %s from %s",
u.Name, u.Location)
}
func NewUser(id int, name, location string) *User {
id++
return &User{id, name, location}
}
func main() {
u := NewUser(42, "Matt", "LA")
fmt.Println(u.Greetings())
}
can inline XXX
The compiler notices that it can inline the NewUser function defined on line 15 and inline it on line 21. Dave Cheney has a great post about why Go’s inlining is helping your programs run faster.
- 関数
XXX
はインライン化の条件を満たしているからインライン化できるよ
inlining call to XXX
-
can inline XXX
は、あくまで「関数XXX
がインライン化の条件を満たしているよ」と言っているだけで、実際にインライン化はされていない -
inlining call to XXX
は、関数XXX
の呼び出し箇所に対して、「実際に関数XXX
の呼び出しをインライン化したよ」という意味
leaking param
On a few lines, you see the potentially alarming leaking param message. It doesn’t mean that there is a memory leak but that the param is kept alive even after returning. The “leaked params” are:
- メモリリークじゃないから安心して
- 関数が終わっても変数が生き続けるよ(golangだと関数内て定義した変数をreturnできる)
X argument does not escape
X argument does not escape means that the argument doesn’t “escape” the function, meaning that it’s not used outside of the function so it’s safe to store it on the stack.
- 変数
X
は関数内でしか使用されていない(からスタックに積めるよ)
X escapes to heap
On the other hand, you can see that &User literal escapes to heap. What it means is that the address of a literal value is used outside of the function and therefore can’t be stored on the stack. The value could be stored on the stack, except a pointer to the value escapes the function, so the value has to be moved to the heap to prevent the pointer referring to incorrect memory once the function returns. This is always the case when calling a method on a value and the method uses one or more fields.
- 変数が関数外で使用されているからスタックに積めない(からヒープに移動するよ)
意外と好評なので追記
インライン化される条件については CompilerOptimizations · golang/go Wiki を参照のこと
Only short and simple functions are inlined. To be inlined a function must contain less than ~40 expressions and does not contain complex things like function calls, loops, labels, closures, panic's, recover's, select's, switch'es, etc.
- 40 行程度より小さい関数じゃなきゃダメ
- 下記が入っててもダメ
- 関数呼び出し
- ループ
- ラベル
- クロージャ
- panic/recover
- select
- switch
結構厳しいなぁ...