gpt4 book ai didi

javascript - 逃逸分析

转载 作者:IT王子 更新时间:2023-10-29 00:52:19 24 4
gpt4 key购买 nike

在很多语言中,局部变量都位于调用栈中

在 JavaScript/Python 中,只有 closure 变量位于堆中,因为它们必须在函数调用之外存在,所以它们被创建。


在 GO 中,一些 GO 类型(如 slice 类型 []int)会引用内存的其他部分,如 JavaScript/Python。

在 GO 中,并非所有类型的变量都包含引用,例如 Javascript/Python。

例如,

1) [3]int 类型变量 b 直接存储一个 int 的数组,像 C 一样,除了 C 允许使用 C 语法 &b[index] 获取每个数组元素位置的访问权限,以获得更多控制

2) int 类型变量 c 直接存储一个int 值,和 C 一样,不同的是,C 通过提供语法 ( &c) 获取位置信息。


在 GO 中,我的理解是,局部变量在堆/堆栈上取决于在示例代码(如下)中应用编译器的逃逸分析

func foo() []int {
// the array lives beyond the call to foo in which it is created
var a [5]int
return a[:] // range operator
}

告诉编译器变量 a 超出了它的范围,所以在堆中分配,而不是堆栈。


问题:

变量 a 是否分配到堆中?

最佳答案

在 Go 中,您应该相信编译器会做出最佳决定。如果可能,它将在堆栈上分配内存。另见 the FAQ :

From a correctness standpoint, you don't need to know. Each variable in Go exists as long as there are references to it. The storage location chosen by the implementation is irrelevant to the semantics of the language.

The storage location does have an effect on writing efficient programs. When possible, the Go compilers will allocate variables that are local to a function in that function's stack frame. However, if the compiler cannot prove that the variable is not referenced after the function returns, then the compiler must allocate the variable on the garbage-collected heap to avoid dangling pointer errors. Also, if a local variable is very large, it might make more sense to store it on the heap rather than the stack.

In the current compilers, if a variable has its address taken, that variable is a candidate for allocation on the heap. However, a basic escape analysis recognizes some cases when such variables will not live past the return from the function and can reside on the stack.


如果不进行优化(内联),是的a会被分配到堆中。我们可以通过传递 -gcflags='-m' ( https://play.golang.org/p/l3cZFK5QHO ) 来检查逃逸分析:

$ nl -ba 1.go
1 package main
2
3 func inlined() []int {
4 var a [5]int
5 return a[:]
6 }
7
8 //go:noinline
9 func no_inline() []int {
10 var b [5]int
11 return b[:]
12 }
13
14 func main() {
15 var local_array [5]int
16 var local_var int
17 println(no_inline())
18 println(inlined())
19 println(local_array[:])
20 println(&local_var)
21 }
$ go build -gcflags='-m' 1.go
# command-line-arguments
./1.go:3: can inline inlined
./1.go:18: inlining call to inlined
./1.go:5: a escapes to heap
./1.go:4: moved to heap: a
./1.go:11: b escapes to heap
./1.go:10: moved to heap: b
./1.go:18: main a does not escape
./1.go:19: main local_array does not escape
./1.go:20: main &local_var does not escape

我们看到编译器决定在堆上分配第 5 行的 inlined.a 和第 10 行的 no_inline.b,因为它们都逃脱了它们的作用域。

但是,在内联之后,编译器发现a 不再转义,因此它确定该变量可以再次分配到堆栈上(第 18 行)。

结果是变量a分配在main goroutine的栈上,而变量b分配在堆上。正如我们从输出中看到的,b 的地址在 0x1043xxxx 上,而所有其他地址都在 0x1042xxxx 上。

$ ./1
[5/5]0x10432020
[5/5]0x10429f58
[5/5]0x10429f44
0x10429f40

关于javascript - 逃逸分析,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41907662/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com