美文网首页go语言学习
go局部变量的存储空间

go局部变量的存储空间

作者: 海豹激凸队 | 来源:发表于2017-10-25 11:13 被阅读40次

读到The Go Programming Language的2.3.2指针一节,我刚在惊讶Go中居然有和C这么像的指针操作,然后就看到了一句话。

函数返回局部变量的地址是非常安全的。

神奇的是,Go编译器会自动选择在栈上还是在堆上分配局部变量的存储空间,但可能令人惊讶的是,这个选择并不是由用var还是new声明变量的方式决定的。如下代码:

var global *int

func f() {
    var x int
    x = 1
    global = &x
}

func g() {
    y := new(int)
    *y = 1
}

f函数里的x变量必须在堆上分配,因为它在函数退出后依然可以通过包一级的global变量找到,虽然它是在函数内部定义的;用Go语言的术语说,这个x局部变量从函数f中逃逸了。相反,当g函数返回时,变量y将是不可达的,也就是说可以马上被回收的。因此,y并没有从函数g中逃逸,编译器可以选择在栈上分配*y的存储空间(译注:也可以选择在堆上分配,然后由Go语言的GC回收这个变量的内存空间),虽然这里用的是new方式。其实在任何时候,你并不需为了编写正确的代码而要考虑变量的逃逸行为,要记住的是,逃逸的变量需要额外分配内存,同时对性能的优化可能会产生细微的影响。

Go语言的自动垃圾收集器对编写正确的代码是一个巨大的帮助,但也并不是说你完全不用考虑内存了。你虽然不需要显式地分配和释放内存,但是要编写高效的程序你依然需要了解变量的生命周期。例如,如果将指向短生命周期对象的指针保存到具有长生命周期的对象中,特别是保存到全局变量时,会阻止对短生命周期对象的垃圾回收(从而可能影响程序的性能)。

知乎布丁的回答:

Go 有 escape analysis, 在编译期,它会分析你的变量是否在函数执行完毕那一刻,程序有没有可能有别的对象引用到它(所谓逃逸),如果没有,那这个变量就可以在栈上分配,完全不经过 gc. 如果它已经逃逸了,那什么时候 gc 就由不得你了。在 go build 时加上 -gcflags='-m' 参数,它会在编译时打印什么东西 escape 了,题主的程序,不好意思,全部中招:
...
原因其实在 fmt.Println, 你看文档,fmt.Println 接收的是 interface{}... Interface 实际上就是个数据指针+itable指针,然后编译器就已经瞎了。所以就只好判断,这时候 j 和 vec 都 escape 了……(叫你不加 generic……)另外注意虽然这时传给 fmt.Println 的 interface{} 并不指向 j, 而是一个 j 的拷贝,但因为编译器已经傻掉,这个拷贝只能放堆上,所以这个 escape 也算在 j 头上了。
伺候 Go gc 最简单的就是少把指针传来传去少弄点零碎共享对象。除了显式指针外 interface{} 是个指针,slice 是个指针 blah blah blah. 没有显著理由优先复制传值而不是传指针,在现代机器上,复制结构往往很廉价(Go 没有复制构造函数之类的东东复制还真就是个 memory copy)。
当然最重要的,做 profiling, 找到真正要优化的点,之后像上面这种静态分析工具也能帮大忙。

最后还看到一个地方,go中的*p++实际上相当于C里的(*p)++即取出此指针指向的值,再将此值+1,而C中的*p++则是取出值,再将指针+1,这点需要注意。

Go语言学习笔记--类型、指针、面向对象

Go 有指针,但是没有指针运算。你不能用指针变量遍历字符串的各个字节.
通过类型作为前缀来定义一个指针’*’:var p *int。现在p 是一个指向整数值的指针。
所有新定义的变量都被赋值为其类型的零值,而指针也一样。一个新定义的或者没有任何指向的指针,有值nil。在其他语言中,这经常被叫做空(NULL)指针,在Go 中就是nil。让指针指向某些内容,可以使用取址操作符(&)

如果一个method的receiver是T,你可以在一个T类型的实例变量V上面调用这个method,而不需要&V去调用这个method
类似的
如果一个method的receiver是T,你可以在一个
T类型的变量P上面调用这个method,而不需要 *P去调用这个method

相关文章

  • go局部变量的存储空间

    读到The Go Programming Language的2.3.2指针一节,我刚在惊讶Go中居然有和C这么像的...

  • 局部变量和全局变量

    什么是局部变量? 在Go语言和C语言中写在{}中或者函数中或者函数的形参, 就是局部变量 什么是全局变量? 在Go...

  • Go 学习

    go语言局部变量分配在栈还是堆Golang 垃圾回收剖析go语言坑之for range

  • 第02天(函数、工程管理)_04

    18_defer和匿名函数结合使用.go 19_获取命令行参数.go 20_局部变量.go 21_全局变量.go ...

  • golang

    go变量 变量的作用域:全局变量和局部变量:局部变量的名称可以和局部变量相同,会根据就近原则使用: 初始值:int...

  • 03-Golang局部变量和全局变量

    局部变量 在C语言中写在{}中或者函数中或者函数的形参, 就是局部变量 Go语言中的局部变量和C语言一样 全局变量...

  • 堆栈 存储空间

    参考文献 iOS--------对堆、栈 存储空间的理解 局部变量、 全局变量、 堆、 堆栈、 静态和全局 iOS...

  • 图解Java内存分析详解一

    A、首先需要明白以下几点: 栈空间(stack),连续的存储空间,遵循后进先出的原则,用于存放局部变量。 堆空间(...

  • go 的内存逃逸

    在C/C++ 中,例如对于局部变量的分配是在栈上,在go语言中,这是不确定的,局部变量的内存分配也许发生在堆上。 ...

  • V8内存管理及垃圾回收机制

    JavaScript引擎的内存空间主要分为栈和堆。 栈 栈是临时存储空间,主要存储局部变量和函数调用。 基本类型数...

网友评论

    本文标题:go局部变量的存储空间

    本文链接:https://www.haomeiwen.com/subject/rofqpxtx.html