gpt4 book ai didi

go - 关于堆栈分配,Go 中的 "small"对象是什么?

转载 作者:IT王子 更新时间:2023-10-29 02:12:30 25 4
gpt4 key购买 nike

代码:

func MaxSmallSize() {
a := make([]int64, 8191)
b := make([]int64, 8192)
_ = a
_ = b
}

然后运行go build -gcflags='-m' . 2>&1检查内存分配细节。结果:

./mem.go:10: can inline MaxSmallSize
./mem.go:12: make([]int64, 8192) escapes to heap
./mem.go:11: MaxSmallSize make([]int64, 8191) does not escape

我的问题是为什么a是小物体,b是大对象吗?

make 64KB 将逃逸到堆中,更少的将分配到堆栈中。 _MaxSmallSize = 32 << 10是什么原因?

go env

GOARCH="amd64"
GOBIN=""
GOEXE=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOOS="linux"
GOPATH="/vagrant/gopath"
GORACE=""
GOROOT="/home/vagrant/go"
GOTOOLDIR="/home/vagrant/go/pkg/tool/linux_amd64"
CC="gcc"
GOGCCFLAGS="-fPIC -m64 -pthread -fmessage-length=0 -fdebug-prefix-map=/tmp/go-build201775001=/tmp/go-build"
CXX="g++"
CGO_ENABLED="1"

最佳答案

由于这在语言规范中没有提及,它是一个实现细节,因此,它可能会因许多因素(Go 版本、目标操作系统、体系结构等)而有所不同。

如果你想找出它的当前值或开始挖掘的地方,请查看 cmd/compile/internal/gc 包。

escape analysis决定在哪里分配变量的是cmd/compile/internal/gc/esc.go .在未导出的函数 esc() 中检查 make slice 操作:

func esc(e *EscState, n *Node, up *Node) {
// ...

// Big stuff escapes unconditionally
// "Big" conditions that were scattered around in walk have been gathered here
if n.Esc != EscHeap && n.Type != nil &&
(n.Type.Width > MaxStackVarSize ||
(n.Op == ONEW || n.Op == OPTRLIT) && n.Type.Elem().Width >= 1<<16 ||
n.Op == OMAKESLICE && !isSmallMakeSlice(n)) {
if Debug['m'] > 2 {
Warnl(n.Lineno, "%v is too large for stack", n)
}
n.Esc = EscHeap
addrescapes(n)
escassignSinkNilWhy(e, n, n, "too large for stack") // TODO category: tooLarge
}

// ...
}

涉及大小的决定在函数 isSmallMakeSlice() 中,这在文件 cmd/compile/internal/gc/walk.go 中:

func isSmallMakeSlice(n *Node) bool {
if n.Op != OMAKESLICE {
return false
}
l := n.Left
r := n.Right
if r == nil {
r = l
}
t := n.Type

return Smallintconst(l) && Smallintconst(r) && (t.Elem().Width == 0 || r.Int64() < (1<<16)/t.Elem().Width)
}

大小限制是这样的:

r.Int64() < (1<<16)/t.Elem().Width

r是 slice 的长度或容量(如果提供了cap),t.Elem().Width是元素类型的字节大小:

NumElem < 65536 / SizeElem

在你的情况下:

NumElem < 65536 / 8 = 8192

因此,如果 slice 类型是 []uint64,则 8192 是它在堆(而不是堆栈)上分配的限制,正如您所经历的那样。

关于go - 关于堆栈分配,Go 中的 "small"对象是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42243197/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com