Deep Engineering

ЗАМЕР

bench/gointerface/escape.sh

Скрипт, которым получены числа в статье, и запись прогона. Файл читается на сборке из репозитория — это тот самый код, который запускали, а не его копия.

Цитируется в статье
/ru/interview/golang/interfaces

Запись прогона

У этого замера записи прогона нет — только скрипт.

Скрипт

43 строк
#!/usr/bin/env bash
#
# Упаковка в интерфейс: что решает тип и что решает escape analysis.
#
# ЗАЧЕМ СКРИПТ. Раздел «ВИД ХРАНЕНИЯ РЕШАЕТ ТИП, ВЫДЕЛЕНИЕ — ESCAPE ANALYSIS»
# в internals.go считает выделения через testing.AllocsPerRun. Это ответ на
# «сколько», но не на «почему». Почему — говорит компилятор: с -gcflags=-m он
# печатает для каждой упаковки, убегает ли копия значения в кучу. Скрипт
# ставит оба вывода рядом, по одним и тем же строкам исходника.
#
# Появился 02.11.2026 в ответ на замечание аудита GO-I01: правило «не указатель
# — значит выделение в куче» ложно на go1.24.7 в обе стороны.
#
# ЗАПУСК:
#
#	bash bench/gointerface/escape.sh
set -u

cd "$(dirname "$0")/../.."
src=bench/gointerface/internals.go

go run "$src" escape

echo
echo "=== РЕШЕНИЯ КОМПИЛЯТОРА: go build -gcflags=-m, строки четырёх случаев ==="
for fn in boxLocalStruct boxEscapingStruct boxPtrField boxIntField; do
  line="$(grep -n "^func $fn()" "$src" | cut -d: -f1)"
  msgs="$(go build -gcflags=-m -o /dev/null "$src" 2>&1 \
    | grep -E "^$src:$line:[0-9]+: " | grep -v "can inline" | sed "s|^$src:||")"
  printf '  %-18s %s\n' "$fn" "$(grep "^func $fn()" "$src" | sed 's/^func [A-Za-z]*() *//')"
  if [ -n "$msgs" ]; then
    printf '%s\n' "$msgs" | sed 's/^/      /'
  else
    echo "      (сообщений об упаковке нет: копии нет, значение хранится прямо)"
  fi
done

echo
echo "  «does not escape» — копия для интерфейса размещена на стеке, отсюда 0."
echo "  «escapes to heap» — копия убегает, отсюда mallocgc и 1 выделение."
echo "  Для Handle компилятору нечего размещать: тип хранится в интерфейсе"
echo "  прямо (types.IsDirectIface), второе слово — сам указатель из поля."