美文网首页
一个Go函数返回值的拷贝问题

一个Go函数返回值的拷贝问题

作者: 自由编程 | 来源:发表于2020-02-26 07:51 被阅读0次

    From - 自由编程


    先提一个问题:一下两段函数,外部调用的时候,返回值会发生值拷贝么?
    代码1

    func r1() (rr1 []mnode) {
        rr1 = append(rr1, mnode{"h1", 1})
        rr1 = append(rr1, mnode{"h2", 2})
        return
    }
    

    代码2

    func r2() (rr2 []*mnode) {
        rr2 = append(rr2, &mnode{"h1", 1})
        rr2 = append(rr2, &mnode{"h2", 2})
        return
    }
    

    用过C语言的同学,可能对代码1多少有点儿疑问,首先这个返回值是分配在堆上还是栈上?返回的时候,会拷贝整个数组么?
    那么我们来分析一下。
    大家都知道,C语言中,临时变量分配在栈中,而通过“new”动作分配出来的变量,则分配在堆中。而Go不同,Go编译器会自动把有必要的临时变量分配在堆中,这个把临时变量分配在堆中的过程,叫做“内存逃逸”。
    下面我们来分析一下函数r1的逃逸过程,首先看test.go文件内容如下:

    package main
    
    import (
        "fmt"
    )
    
    type mnode struct {
        name string
        id   int
    }
    
    func r1() (rr1 []mnode) {
        rr1 = append(rr1, mnode{"h1", 1})
        rr1 = append(rr1, mnode{"h2", 2})
        return
    }
    
    func main() {
        mr1 := r1()
        fmt.Println(mr1)
    }
    
    

    我们通过下面的命令行来进行整个程序的逃逸分析。

    go build -gcflags '-m -l' test.go 
    

    输出

    # command-line-arguments
    ./test.go:20:13: main ... argument does not escape
    ./test.go:20:13: mr1 escapes to heap
    

    这里可以看出,变量mr1已经分配在堆上了
    简单分析一下现在mr1和rr1内存分配情况,把rr1和mr1的地址打印出来看一下

    package main
    
    import (
        "fmt"
    )
    
    type mnode struct {
        name string
        id   int
    }
    
    func r1() (rr1 []mnode) {
        rr1 = append(rr1, mnode{"h1", 1})
        rr1 = append(rr1, mnode{"h2", 2})
        fmt.Printf("ptr-rr1: %p \n", &rr1)
        fmt.Printf("ptr-rr1[1]: %p \n", &(rr1[1]))
    
        return
    }
    
    func main() {
        mr1 := r1()
        fmt.Println("---------")
        fmt.Printf("ptr-mr1: %p \n", &mr1)
        fmt.Printf("ptr-mr1[1]: %p \n", &(mr1[1]))
    }
    

    然后执行 go run test.go,得到如下结果

    $ go run test.go
    ptr-rr1: 0xc00000c0a0 
    ptr-rr1[1]: 0xc000064198 
    ---------
    ptr-mr1: 0xc00000c080 
    ptr-mr1[1]: 0xc000064198 
    

    可以看到rr1和mr1的地址确实不同,但里面元素的地址

    相关文章

      网友评论

          本文标题:一个Go函数返回值的拷贝问题

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