Почему в make ([] int, 14) есть runtime.morestack, а в make ([] int, 13) нет? - PullRequest
0 голосов
/ 01 февраля 2019

Я уже знал, что runtime.morestack вызовет переключение контекста goroutine (если sysmon goroutine пометил, что он должен переключаться).

И когда я провожу некоторый эксперимент по этому поводу, я 'Мы нашли интересный факт.

Сравните следующие коды.

func main() {
    _ = make([]int, 13)
}

func main() {
    _ = make([]int, 14)
}

И скомпилируйте их, выполнив следующую команду: (Попробовал в go1.9 и перейти 1.11)

$ go build -gcflags "-S -l -N" x.go

Вы можете обнаружить существенную разницу в том, что первый выход содержит CALL runtime.morestack_noctxt(SB), а второй - нет.

Я полагаю, что это оптимизация, но почему?

1 Ответ

0 голосов
/ 02 февраля 2019

Наконец, я получил ответ.

  • Создание среза, который меньше 65 536 байт и не экранируется от функции, будет выделен в стеке, а не в куче.

  • StackGuard0 будет выше самого низкого адреса стека как минимум на 128 байтов.(Даже после сокращения)

  • make ([] int, 13) в общей сложности выделит 128 байтов памяти.

sizeof (struct slice) + 13 * 8 = 24 + 104 = 128.

Таким образом, ответ ясен, это оптимизация для amd64.

Для функции листьев, еслион использовал менее 128 байтов памяти, компилятор не генерировал бы коды, которые проверяют, не переполнен ли стек (потому что места достаточно).

Вот объяснение в go/src/runtime/stack.go

Для goroutine g-> stackguard настроено указывать байты StackGuard над дном стека.Каждая функция сравнивает свой указатель стека с g-> stackguard для проверки на переполнение.Чтобы вырезать одну инструкцию из контрольной последовательности для функций с крошечными кадрами, стеку разрешено выдвигать байты StackSmall ниже стекового сторожа.Функции с большими кадрами не мешают проверке и всегда вызывают morestack.Последовательности (для amd64, другие похожи):

...