Memory Go内存布局与C++/C

Memory Go内存布局与C++/C,memory,layout,go,Memory,Layout,Go,在Go中,似乎没有构造函数,但建议您使用函数分配结构类型的对象,例如,通常以“New”+TypeName”命名 func NewRect(x,y, width, height float) *Rect { return &Rect(x,y,width, height) } 但是,我不确定Go的内存布局。在C/C++中,这类代码意味着您返回一个指针,该指针指向一个临时对象,因为变量是在堆栈上分配的,并且在函数返回后该变量可能是一些垃圾。在围棋中,我需要担心这样的事情吗?因为似乎

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

func NewRect(x,y, width, height float) *Rect {
     return &Rect(x,y,width, height)
}
但是,我不确定Go的内存布局。在C/C++中,这类代码意味着您返回一个指针,该指针指向一个临时对象,因为变量是在堆栈上分配的,并且在函数返回后该变量可能是一些垃圾。在围棋中,我需要担心这样的事情吗?因为似乎没有标准显示将在堆栈上分配什么样的数据,而不是在堆上分配什么样的数据

在Java中,似乎有一个特定的点,即int、float等基本类型将在堆栈上分配,从该对象派生的其他对象将在堆上分配。在围棋中,是否有关于这一点的具体讨论?

提到:

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

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

在函数调用中,函数值和参数按通常顺序求值。
求值后,调用的参数按值传递给函数,被调用函数开始执行。
当函数返回时,函数的返回参数按值传回调用函数

你可以看到更多和更多

如“”所述:

值得注意的是,“stack”和“heap”这两个词并没有出现在语言规范中的任何地方


具体发生了什么

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

这篇博文补充道:

执行“转义分析”的代码位于
从概念上讲,它试图确定局部变量是否逃逸当前范围;只有两种情况会发生这种情况,一种是返回变量的地址,另一种是将其地址分配给外部作用域中的变量。
如果变量转义,则必须在堆上分配它;否则,将其放在堆栈上是安全的

有趣的是,这也适用于
new(T)
分配。
如果它们不逃逸,它们最终将被分配到堆栈上。下面是一个澄清问题的例子:

var intPointerGlobal *int = nil

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

    anInt2 := 42
    intPointerGlobal = &anInt2

    anInt3 := 5

    return &anInt3
}
上面,
anInt0
anInt1
没有转义,因此它们被分配到堆栈上
anInt2
anInt3
转义,并在堆上分配


另见“”:

与C不同的是,Go实现了一种称为escape analysis的优化,C强制您选择是通过
malloc
将值存储在堆上,还是通过在函数范围内声明值存储在堆栈上

默认情况下,Go的优化始终处于启用状态。
您可以使用
-gcflags=-m
开关查看编译器的转义分析和内联决策

因为转义分析是在编译时而不是运行时执行的,所以不管垃圾收集器的效率有多高,堆栈分配总是比堆分配快


它将被分配到堆上。Go编译器可以检测对象何时位于堆栈之外,并自动在堆上分配它。如果您使用
go build-gcflags'-m'
进行编译以查看优化决策,您就可以看到它。@python:您的直觉是正确的,您不必担心它。实际上,它确实是在堆上分配的,但是Go的内存模型非常简单,实际上根本不需要考虑堆栈和堆。你可以只考虑变量。如果您获取某物的地址,Go将保证该地址始终有效,只要您有指向该地址的指针。作为一名程序员,这对你来说并不重要。(虽然,很明显,想想它是如何实现的可能会很有趣,而且那里也有一些很酷的东西)谢谢你们所有的人answer@synful“如果您获取某个对象的地址,Go将保证该地址始终有效,只要您有指向该地址的指针”。。。好吧,除了指向某个复合文字的指针,比如
x:=&((2*3)+4)
:是的,但是Go不会盲目地让你这么做,并且会有运行时错误-它不会让你编译它。即使规范没有提到它,编译器也会在其转义分析中执行:
/test.Go:11:new(int)转义到heap
@siritinga。我对答案进行了编辑,添加了更多关于逃逸分析的细节,这只是一个评论。最后,要避免使用堆/堆栈术语并非易事:)@siritinga是的,但表明goroutine堆栈与普通堆栈(非常小,没有保护页,…)@VonC note to self,这是我的第1000个好答案。