Каково значение вывода "go run -gcflags -m xxx.go"
Попытка проверить, размещена ли локальная переменная в куче или стеке в программе go, и не может быть уверенным в значении какого-либо вывода из go gc.
Код
variable_heap_stack.go:
// variable heap & stack learn,
// run with:
// go run -gcflags -m xxx.go
package main
import "fmt"
func getPointerOfLocalVar() *int {
x := 10 // go will put it into heap,
return &x
}
// heap & stack test,
func heapStackTest() {
px := getPointerOfLocalVar()
fmt.Printf("x: %d\n", *px)
y := 20 // go will put it into stack,
fmt.Printf("y: %d\n", y)
}
func main() {
heapStackTest()
}
Выполнение:
запустите -gcflags -m variable_heap_stack.go
Выход:
# command-line-arguments
./variable_heap_stack.go:8:6: can inline getPointerOfLocalVar
./variable_heap_stack.go:15:28: inlining call to getPointerOfLocalVar
./variable_heap_stack.go:10:9: &x escapes to heap
./variable_heap_stack.go:9:6: moved to heap: x
./variable_heap_stack.go:16:24: *px escapes to heap
./variable_heap_stack.go:19:13: y escapes to heap
./variable_heap_stack.go:15:28: heapStackTest &x does not escape
./variable_heap_stack.go:16:12: heapStackTest ... argument does not escape
./variable_heap_stack.go:19:12: heapStackTest ... argument does not escape
x: 10
y: 20
Вопросы
- Что значит
escapes to heap
имею в виду? Это будет куча или нет? moved to heap
, это значит двигаться в кучу, верно? Какая разница с вышеупомянутым?y
переменная является локальной, никто не обращается к ней после возврата функции, но там все еще есть строкаy escapes to heap
зачем это было?
1 ответ
Что значит
escapes to heap
имею в виду? Это будет куча или нет?
Это означает, что значение, указанное в сообщении, покидает "границы" функции, и поэтому не может быть гарантировано, что происходит с ним вне функции, поэтому, если значение является указателем или ссылкой (но только тогда), Указанное или ссылочное значение должно быть выделено в куче.
Вы можете думать о escapes to heap
как отладочное сообщение, это не означает, что одна из ваших переменных "перемещена" в кучу.
Проще говоря, "убегает в кучу" аналогично термину: "он покидает функцию" или "он передается вне функции".
В качестве примера эта строка:
./variable_heap_stack.go:16:24: *px escapes to heap
Говорит что значение *px
передается за пределы функции, а именно как аргумент fmt.Printf()
в этой строке:
fmt.Printf("x: %d\n", *px)
moved to heap
, это значит двигаться в кучу, верно? Какая разница с вышеупомянутым?
Это указывает на то, что компилятор решил переместить указанную в сообщении переменную в кучу, поскольку на нее можно ссылаться вне функции, и, следовательно, он должен пережить функцию. А поскольку значения, выделенные стеком, могут стать недействительными после возврата из функции, чтобы указанная переменная была действительной после возврата из функции, она должна находиться в куче.
Moved to heap
это прямое объявление о том, что одна из ваших переменных действительно "перемещена" в кучу. Примечание. "Перемещено" означает, что переменная будет размещена в куче в первую очередь, фактическое "перемещение" не произойдет в любом случае.
y
переменная является локальной, никто не обращается к ней после возврата функции, но там все еще есть строкаy escapes to heap
зачем это было?
Как упоминалось ранее, это не значит, y
перемещается в кучу, это означает только значение y
передается за пределы функции, а именно как параметр fmt.Printf()
в этой строке:
fmt.Printf("y: %d\n", y)
y
не будет перемещен в кучу только из-за этого, в этом нет необходимости, так как он передается fmt.Printf()
сделав копию его стоимости, и fmt.Printf()
не будет возможности добраться до вашего y
локальная переменная.
Совет:
Вы можете получить более подробную информацию об оптимизации решений и избежать анализа, передав -m
в два раза так:
go run -gcflags='-m -m' variable_heap_stack.go
Тогда результат этой команды будет:
./variable_heap_stack.go:8:6: can inline getPointerOfLocalVar as: func() *int { x := 10; return &x }
./variable_heap_stack.go:14:6: cannot inline heapStackTest: non-leaf function
./variable_heap_stack.go:15:28: inlining call to getPointerOfLocalVar func() *int { x := 10; return &x }
./variable_heap_stack.go:22:6: cannot inline main: non-leaf function
./variable_heap_stack.go:10:9: &x escapes to heap
./variable_heap_stack.go:10:9: from ~r0 (return) at ./variable_heap_stack.go:10:2
./variable_heap_stack.go:9:2: moved to heap: x
./variable_heap_stack.go:16:24: *px escapes to heap
./variable_heap_stack.go:16:24: from ... argument (arg to ...) at ./variable_heap_stack.go:16:12
./variable_heap_stack.go:16:24: from *(... argument) (indirection) at ./variable_heap_stack.go:16:12
./variable_heap_stack.go:16:24: from ... argument (passed to call[argument content escapes]) at ./variable_heap_stack.go:16:12
./variable_heap_stack.go:19:13: y escapes to heap
./variable_heap_stack.go:19:13: from ... argument (arg to ...) at ./variable_heap_stack.go:19:12
./variable_heap_stack.go:19:13: from *(... argument) (indirection) at ./variable_heap_stack.go:19:12
./variable_heap_stack.go:19:13: from ... argument (passed to call[argument content escapes]) at ./variable_heap_stack.go:19:12
./variable_heap_stack.go:15:28: heapStackTest &x does not escape
./variable_heap_stack.go:16:12: heapStackTest ... argument does not escape
./variable_heap_stack.go:19:12: heapStackTest ... argument does not escape
x: 10
y: 20