Поскольку это не упоминается в спецификации языка, это деталь реализации, и поэтому она может варьироваться в зависимости от ряда факторов (версия Go, целевая ОС, архитектура и т. д.).
Если вы хотите узнать его текущее значение или место, с которого можно начать копать, ознакомьтесь с пакетом cmd/compile/internal/gc
.
анализ экранирования, который решает, где разместить переменную, находится в cmd/compile/internal/gc/esc.go
. Проверка операции создания слайса находится в неэкспортированной функции esc()
:
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
— длина или емкость слайса (если указано ограничение), t.Elem().Width
— размер элемента в байтах:
NumElem < 65536 / SizeElem
В твоем случае:
NumElem < 65536 / 8 = 8192
Таким образом, если тип среза — []uint64
, 8192 — это предел, от которого он выделяется в куче (а не в стеке), как вы уже поняли.
person
icza
schedule
15.02.2017