golang内存逃逸分析

一、编译器的逃逸分析

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编译器会对一些小函数进行内联优化,以提升性能。内联优化意味着函数的代码会在调用处直接展开,而不是常规的函数调用。这就导致一些逃逸分析的行为发生变化,类似上面那个代码的内存地址就会是连续的。

什么时候编译器会进行内联优化?

  1. 函数体较小:Go编译器更容易将体积较小的函数进行内联
  2. 无复杂控制结构:如果函数内没有复杂的循环,条件分支等……内联的可能性更高
  3. 函数参数和返回值简单:函数参数和返回值不过于复杂也有助于函数的内联

二、new的变量内存分配在栈还是堆上?

new 出来的变量,内存一定是分配在堆上吗?

还是原来的代码,我们通过new 分开来看看:

package main

func main() {
   
   
	// 打印返回的指针地址
	println(fool())
	// 0x1400001a0a0
}

//go:noinline    内置的编译指令,可以强制让 Go 编译器不对指定的函数进行内联优化
func fool() *int {
   
   
	var (
		a = new(int
在Go语言中,内存逃逸指的是当一个对象的指针被多个方法或线程引用时,这个指针会逃逸到堆上。内存逃逸的位置由编译器决定,而不像C或C++可以使用malloc或new在堆上分配内存。根据内存分配的基本原则,当函数外部对指针没有引用时,优先分配在栈上;当函数外部对指针存在引用时,优先分配在堆上;当函数内部分配一个较大对象时,优先分配在堆上。\[1\] 在Go语言中,内存逃逸分析可以通过一些规则来判断。例如,当使用等号=赋值时,如果Data和Field都是引用类型的数据,则会导致Value逃逸。另外,一些特定的数据类型也会导致逃逸,比如\[\]interface{}、map\[string\]interface{}、map\[interface{}\]interface{}、map\[string\]\[\]string、map\[string\]*int、\[\]*int、func(*int)、func(\[\]string)、chan \[\]string等。具体的规则可以参考引用\[2\]中的示例。\[2\] 此外,栈空间不足也可能导致内存逃逸。当在函数中创建一个较大的切片或数组,并且栈空间不足以容纳它们时,这些切片或数组会逃逸到堆上。例如,在一个函数中创建一个长度为10000的切片,如果栈空间不足,这个切片就会逃逸到堆上。\[3\] 总结来说,内存逃逸是指当一个对象的指针被多个方法或线程引用时,这个指针会逃逸到堆上。在Go语言中,内存逃逸的位置由编译器决定,可以通过一些规则和栈空间的判断来进行分析。 #### 引用[.reference_title] - *1* [golang内存逃逸分析](https://blog.youkuaiyun.com/qq_42170897/article/details/127770234)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [golang内存逃逸](https://blog.youkuaiyun.com/wanghao3616/article/details/107284523)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [golang——内存逃逸机制](https://blog.youkuaiyun.com/weixin_45627369/article/details/127163797)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

疯狂的程需猿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值