在Go语言中,无需担心堆栈和堆的问题
我想查找的原因是在golang中,可以将局部变量的地址作为返回值而没有问题。
package main
import (
"fmt"
)
type Animal struct {
Name string
Age int
}
func main() {
animal := allocAnimal()
fmt.Printf("allocate animal structure %p", animal)
}
func allocAnimal() *Animal {
return &Animal{}
}
在C/C++中,当将局部变量的指针作为返回值时,由于需要将栈区的指针传递给函数外部,在编译时会显示警告信息(为什么不报错)。
在执行时最糟糕的情况是会发生段错误。
因此,需要使用malloc或new在堆区分配内存。
我很好奇为什么在Golang中允许这样做,所以进行了调查。
关于堆栈和堆的问题
以下是关于Golang中堆栈和堆的简要解释。
堆栈
-
- 確保・解放が早い
-
- 寿命が短い。関数内もしくは特定のスコープ内限定
-
- サイズが小さい
- ローカル変数・引数などで使われる
堆
-
- 確保・解放が遅い
-
- 寿命は自由
-
- サイズが大きい
- newなどで確保される
Golang的常见问题解答
请在Golang的FAQ中查看有关堆栈和堆的处理的详细说明。请查看链接以获取完整内容。
在Go语言中,栈和堆的使用方式是如何的?
如果要确保正确性,就不需要知道。只要引用了Go的每个变量,它就会一直存在。在Go语言中,被选择的存储位置没有任何意义。
根据编译器的判断,如果变量的作用范围限定在函数内部,则被存储在栈中;如果变量在函数外也被引用,会被分配到堆中作为局部变量。
我实际上进行了调查。
当您向编译器传递标志时,您将了解内存分配的情况。
执行一下命令编译hello.go文件:go build -gcflags -m hello.go
我們來看一下原封不動的示範代碼。
$ go build -gcflags -m main.go
./main.go:17: can inline allocAnimal
./main.go:13: inlining call to allocAnimal
./main.go:14: animal escapes to heap
./main.go:13: &Animal literal escapes to heap
./main.go:14: main ... argument does not escape
./main.go:18: &Animal literal escapes to heap // ローカル変数がヒープに
在评论部分,编译器判断函数在外部处理,并在堆而非栈上分配空间。
如果你不将在函数外部分配的内存释放,-如果你没有释放在函数外部分配的内存,
那么,如果把代码改成下面这样会怎么样呢?
func allocAnimal() *Animal {
animal := new(Animal)
animal.Name = "Cat"
animal.Age = 23
return &Animal{}
}
这段代码的内容并没有太多意义,但是在函数内部使用了刚创建的对象来完成任务。
我将再次输出这段代码的状态。
./main.go:17: can inline allocAnimal
./main.go:13: inlining call to allocAnimal
./main.go:14: animal escapes to heap
./main.go:13: &Animal literal escapes to heap
./main.go:13: main new(Animal) does not escape // newしてもヒープに割り当てられない
./main.go:14: main ... argument does not escape
./main.go:22: &Animal literal escapes to heap
./main.go:18: allocAnimal new(Animal) does not escape
在Go语言中,对于在函数内部完成的对象,即使使用new方式进行分配,它们也会被分配到栈上,而不是堆上。
在Go语言中,似乎不需要特别意识到是使用堆还是栈的问题,这一点并不会引起太多困惑,尽管对于长期从事C/C++的人来说可能会感到疑惑。