#go #escape-analysis
# #Вперед #escape-анализ
Вопрос:
Я не совсем понимаю, почему анализ экранирования Go говорит, что локальная целочисленная переменная экранируется в кучу, когда она передается fmt.Fprintln
, в то время как она не экранируется, когда она передается другой самописной функции с той же сигнатурой, fmt.Fprintln
что и . Я надеюсь, что два сценария A и B, приведенные ниже, должны прояснить проблему.
Сценарий A: x
экранирование в кучу
Возьмите следующее содержимое main.go
:
package main
import (
"fmt"
"os"
)
func main() {
x := 73
fmt.Fprintln(os.Stdout, x)
}
Когда вы теперь запускаете go build -gcflags "-m"
, вы видите вывод, который указывает, что x
экранирование выполняется в кучу. В выводе говорится что-то вроде
...
.main.go:10:14: x escapes to heap
...
Сценарий B: x
не экранируется в кучу
Теперь возьмем следующее содержимое main.go
:
package main
import (
"io"
"os"
)
func main() {
x := 73
myOwnPrintFunction(os.Stdout, x)
}
//go:noinline
func myOwnPrintFunction(w io.Writer, a ...interface{}) {
println(a)
}
При повторном запуске go build -gcflags "-m"
вы видите вывод, который указывает, что x
он больше не экранируется в кучу. Теперь вывод говорит что-то вроде
...
.main.go:10:20: x does not escape
...
Я не понимаю здесь разницы. Я бы подумал, что сценарий A правильный, поскольку x
передается переменной функции, которая принимает произвольное количество interface{}
аргументов. Но, по-видимому, это неправильно, поскольку переменная больше не экранируется, когда она передается самописной функции myOwnPrintFunction
, которая также является переменной функцией, принимающей произвольное количество interface{}
аргументов, и где компилятору дано указание не вводить эту простую функцию.
Комментарии:
1. Это неуказанная деталь реализации и зависит от используемого компилятора. Основной причиной может быть то, что fmt.Fprintln делает гораздо больше, чем println . Все это не имеет ничего общего с тем, как вызывается функция, или если это ваша собственная функция или из stdlib, но если анализ escape может доказать, что переменная может быть выделена стеком.