与C++/C相比,Golang内存布局

pyt*_*hon 16 memory layout go

在golang中,似乎没有构造函数,但建议您使用函数分配结构类型的对象,通常以"New"+ TypeName命名,例如

func NewRect(x,y, width, height float) *Rect {
     return &Rect(x,y,width, height)
}
Run Code Online (Sandbox Code Playgroud)

但是,我不确定Go的内存布局.在C/C++中,这种代码意味着您返回一个指向临时对象的指针,因为该变量是在堆栈上分配的,并且该函数在函数返回后可能是一些垃圾.在Golang,我是否必须担心这种事情?因为似乎没有标准显示将在堆栈上分配什么类型的数据与将在堆上分配什么类型的数据.

就像在Java中一样,似乎有一个特定的指出,基本类型如int,float将在堆栈上分配,从该对象派生的其他对象将在堆上分配.在golang,有没有具体谈论这个?

Von*_*onC 29

复合声明部分中提到:

获取复合文字的地址(§Address运算符)会生成一个指向文字值实例的唯一指针.

这意味着New函数返回的指针将是有效的(在堆栈上分配).
电话:

在函数调用中,函数值和参数按通常顺序计算.
在评估它们之后,调用的参数通过值传递给函数,并且被调用的函数开始执行.
当函数返回时,函数的返回参数通过值传递回调用函数.

你可以在这个答案这个帖子中看到更多.

如" Go中的结构与堆结构分配,以及它们与垃圾收集的关系 "中所述:

值得注意的是,"堆栈"和"堆"这两个词在语言规范中没有出现.


博客文章"逃逸分析中转到"细节发生了什么,提的常见问题:

如果可能,Go编译器将为该函数的堆栈帧中的函数分配本地变量.
但是,如果编译器在函数返回后无法证明变量未被引用,则编译器必须在垃圾收集堆上分配变量以避免悬空指针错误.
此外,如果局部变量非常大,将它存储在堆而不是堆栈上可能更有意义.

博客文章补充说:

执行"转义分析"的代码位于src/cmd/gc/esc.c中.
从概念上讲,它试图确定局部变量是否转义当前范围; 发生这种情况的唯一两种情况是返回变量的地址,以及将其地址分配给外部作用域中的变量.
如果变量转义,则必须在堆上分配; 否则,把它放在堆栈上是安全的.

有趣的是,这也适用于new(T)分配.
如果它们没有逃脱,它们最终会被分配到堆栈中.这是一个澄清问题的例子:

var intPointerGlobal *int = nil

func Foo() *int {
    anInt0 := 0
    anInt1 := new(int)

    anInt2 := 42
    intPointerGlobal = &anInt2

    anInt3 := 5

    return &anInt3
}
Run Code Online (Sandbox Code Playgroud)

上面,anInt0anInt1没有逃脱,所以他们被分配在堆栈上;
anInt2anInt3转义,并在堆上分配.


另请参阅" 快速行动的五件事 ":

与C不同,它强制您选择是将值存储在堆上,通过malloc堆栈还是堆栈上,通过在函数范围内声明它,Go实现了一个名为转义分析的优化.

默认情况下,Go的优化始终处于启用状态.
您可以通过-gcflags=-m交换机查看编译器的转义分析和内联决策.

因为转义分析是在编译时执行的,而不是运行时,所以无论垃圾收集器的效率如何,堆栈分配总是比堆分配快.

  • @VonC注意到自己,那是我的第1000个好答案. (2认同)