一、编译器的逃逸分析
go语言编译器会自动决定把一个变量放在堆上还是放在栈上,编译器会做逃逸分析,当发现变量的作用域没有跑出函数范围(悬空指针),就可以在栈上,否则则必须分配在堆上。
这样可以释放程序员关于内存的使用限制,更多的让程序员关注于程序功能逻辑本身。
我们看如下代码:
package main
func main() {
// 打印返回的指针地址
println(fool())
// 0x1400008e000
}
//go:noinline 内置的编译指令,可以强制让 Go 编译器不对指定的函数进行内联优化
func fool() *int {
var (
a = 1
b = 2
c = 3
d = 4
e = 5
)
println(&a, &b, &c, &d, &e)
// 0x14000066f38 0x14000066f30 0x1400008e000 0x14000066f28 0x14000066f20
return &c
}
我们能看到**c**是返回给main 的局部变量,其中它的地址值是 0x1400008e000 很明显与其他的 a b d e 不是连续的。
我们用go tool compile测试一下
~/workspace/test go tool compile -m main.go
main.go:3:6: can inline main
main.go:14:3: moved to heap: c
果然,在编译的时候,c 被编译器判定为逃逸变量,将c 放在堆中开辟
内联: go编译器会对一些小函数进行内联优化,以提升性能。内联优化意味着函数的代码会在调用处直接展开,而不是常规的函数调用。这就导致一些逃逸分析的行为发生变化,类似上面那个代码的内存地址就会是连续的。
什么时候编译器会进行内联优化?
- 函数体较小:Go编译器更容易将体积较小的函数进行内联
- 无复杂控制结构:如果函数内没有复杂的循环,条件分支等……内联的可能性更高
- 函数参数和返回值简单:函数参数和返回值不过于复杂也有助于函数的内联
二、new的变量内存分配在栈还是堆上?
new 出来的变量,内存一定是分配在堆上吗?
还是原来的代码,我们通过new 分开来看看:
package main
func main() {
// 打印返回的指针地址
println(fool())
// 0x1400001a0a0
}
//go:noinline 内置的编译指令,可以强制让 Go 编译器不对指定的函数进行内联优化
func fool() *int {
var (
a = new(int

最低0.47元/天 解锁文章
841

被折叠的 条评论
为什么被折叠?



