GO语音的内存逃逸

面试的时候面试官就喜欢问一个问题 为什么go语音不分堆和栈

屁话  go语音是分堆和栈的

只是go语音开发者,用内存逃逸机制 , 使得大家认为go语音不分堆和栈

 

开始教学

内存中分为堆和栈:

我们定义的变量会分配堆或者栈上:

具体有一些规则:

例如c语言:

  1. new关键字,那么就一定分配在堆上

  2. 堆上面的数据,如果不手动释放,会与程序共存亡(内存泄露)

  3. 栈上的数据,会有自己的作用域,只要退出作用域,系统自动释放。

 

go语言有gc机制,可以自动回收内存。

 

go语言在编译的时候,就会确定一个变量是否分配在堆上还是栈上。规则如下:

  1. 如果变量在其他地方(非局部)被引用,那么就一定分配在堆上,否则分配在栈上。

  2. 即使没有被外部引用,但是对象过大,无法存在栈上,那么就分配在堆上。

 

 

什么是逃逸分析

变量分配在堆上,不分配在栈上,这种现象叫做内存逃逸。

案例分析

案例一:被局部变量引用时逃逸

test1.go

package main

type People struct {
	Name string
	Age  int
}

func getInfo() *People {

	//perple在函数内部创建,属于局部变量,但是在getInfo函数之外引用了
	//此时,编译器会将people变量分配到堆上
	return &People{
		Name: "Lily",
		Age:  20,
	}
}

func main() {
	_ = getInfo()
}

方式1:

go build --gcflags "-m -m -l" test1.go

方式2:

go tool compile -S test1.go

案例二:未确定类型时逃逸

package main

import "fmt"

func main() {
	//使用new关键字,也不一定分配到堆上
	//由于在main之外没有使用过str这个变量,所有分配到栈上
	str := new(string)
	*str = "hello"
}
duke@DUKEDU51C6 MINGW64 /c/goprojects/src/test
$ go build -gcflags "-m -m -l" test2.go
# command-line-arguments
.\test2.go:6:12: main new(string) does not escape

加上printf函数后,内存逃逸发生,因为printf里面接收interface,类型不明确,所以逃逸:

package main
​
import "fmt"
​
func main() {
    //使用new关键字,也不一定分配到堆上
    //由于在main之外没有使用过str这个变量,所有分配到栈上
    str := new(string)
    *str = "hello"
    fmt.Printf("str :%s, ", str)
}

 

duke@DUKEDU51C6 MINGW64 /c/goprojects/src/go5期/03-比特币/test
$ go build -gcflags "-m -m -l" test2.go
# command-line-arguments
.\test2.go:11:13: str escapes to heap
.\test2.go:11:13:       from ... argument (arg to ...) at .\test2.go:11:12
.\test2.go:11:13:       from *(... argument) (indirection) at .\test2.go:11:12
.\test2.go:11:13:       from ... argument (passed to call[argument content escapes]) at .\test2.go:11:12
.\test2.go:8:12: new(string) escapes to heap
.\test2.go:8:12:        from str (assigned) at .\test2.go:8:6

案例三:泄露参数时不逃逸

package main
​
type People1 struct {
    Name string
    Age  int
}
​
//不逃逸
func getInfo1(p *People1) *People1 {
    return p
}
​
func getInfo2(p People1) *People1 {
    return &p
}
​
func main() {
    p1 := People1{
        Name: "Lily",
        Age:  20,
    }
    _ = getInfo1(&p1) //没逃逸
​
    _ = getInfo2(p1) //逃逸
}

总结:

  1. 分配到栈上,性能一定比动态分配到堆上好。

  2. 具体分配到堆还是栈,对于编程人员是不可见的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在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.csdn.net/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.csdn.net/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.csdn.net/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 ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值