在Go语言中初始化对象时,堆和栈的概念存在吗?

huangapple go评论84阅读模式
英文:

Initializing objects in GoLang - Heap/stack does that concept exist?

问题

我刚刚开始学习Go语言。我注意到有一些初始化的方式如下:

agentUi := &f.Foo{
    Reader:      os.Stdin,
    Writer:      os.Stdout,
    ErrorWriter: os.Stderr,
}

作为一个来自C++背景的人,我认为上述的原因是开发者想要创建一个指向agentUi的指针,而不是一个对象。如果是这样的话,他本可以这样做:

agentUi := f.Foo{
    Reader:      os.Stdin,
    Writer:      os.Stdout,
    ErrorWriter: os.Stderr,
}

这样做的目的是确保对象在作用域结束后仍然有效,简而言之,将对象创建在堆上而不是栈上。这样理解对吗?

英文:

I just started with GoLang. I have noticed there are some initializations like this

agentUi := &f.Foo{
		Reader:      os.Stdin,
		Writer:      os.Stdout,
		ErrorWriter: os.Stderr,
	}

Coming from a c++ background , I am under the impression the reason above was done because the developer wanted to create a pointer agentUi instead of an object where he could have done something like this

agentUi := f.Foo{
		Reader:      os.Stdin,
		Writer:      os.Stdout,
		ErrorWriter: os.Stderr,
	}

so basically making sure that the object is still valid after the scope ends.In short create the object on the heap instead of the stack.
Is that correct ?

答案1

得分: 2

Go语言不允许直接控制内存的分配位置。

如果你没有使用引用,内存会从栈上分配。

如果你在传递引用,编译器会进行逃逸分析,尝试从栈上分配内存,但如果失败了,内存会从堆上分配。

你可以使用-gcflags '-m -l'来查看程序的逃逸分析。

例如,验证下面程序的逃逸分析。

package main

import (
	"fmt"
	"io"
	"os"
)

func main() {
	fmt.Printf("%v\n", work())
}

type Foo struct {
	Reader      io.Reader
	Writer      io.Writer
	ErrorWriter io.Writer
}

func work() *Foo {
	agentUi := &Foo{
		Reader:      os.Stdin,
		Writer:      os.Stdout,
		ErrorWriter: os.Stderr,
	}
	return agentUi
}

输出:

$ go run -gcflags '-m -l' main.go
# command-line-arguments
./main.go:20:13: &Foo{...} escapes to heap
./main.go:10:12: ... argument does not escape
&{0xc00000e010 0xc00000e018 0xc00000e020}
英文:

Go does not allow direct control over where the memory you use is allocated.

If you aren't using references, the memory is allocated from the stack.

If you are passing references around, the compiler does escape analysis in order to try to allocate from the stack, but failing that, the memory is allocated on the heap.

You can use -gcflags '-m -l' to see escape analysis for your program.

go run -gcflags '-m -l' main.go

For instance, verifying escape analisys on the program below.

package main

import (
	"fmt"
	"io"
	"os"
)

func main() {
	fmt.Printf("%v\n", work())
}

type Foo struct {
	Reader      io.Reader
	Writer      io.Writer
	ErrorWriter io.Writer
}

func work() *Foo {
	agentUi := &Foo{
		Reader:      os.Stdin,
		Writer:      os.Stdout,
		ErrorWriter: os.Stderr,
	}
	return agentUi
}

Output:

$ go run -gcflags '-m -l' main.go
# command-line-arguments
./main.go:20:13: &Foo{...} escapes to heap
./main.go:10:12: ... argument does not escape
&{0xc00000e010 0xc00000e018 0xc00000e020}

huangapple
  • 本文由 发表于 2022年5月15日 09:52:36
  • 转载请务必保留本文链接:https://go.coder-hub.com/72245044.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定