BackendBit

К глоссарию

Машинное слово

Другие названия
machine word
слово
word

Машинное слово – единица данных, с которой процессор работает за одну операцию. Размер слова равен разрядности регистров общего назначения: 4 байта на 32-битных процессорах и 8 байт на 64-битных.

Размер слова

Указатель хранит адрес в памяти, а адрес обычно помещается в один регистр. Поэтому указатель занимает одно слово. Словами удобно мерить структуры из указателей и полей типа int: в словах их размер одинаков на всех платформах, а в байтах зависит от архитектуры процессора.

Машинное слово в Go

Спецификация Go задаёт размер uint нестрого – 32 или 64 бита; int занимает столько же, а uintptr вмещает любой указатель. Стандартный компилятор gc выбирает размер слова платформы, поэтому int, uint, uintptr и указатели занимают ровно одно слово: 4 байта на 32-битных платформах (386, arm) и 8 байт на 64-битных (amd64, arm64).

Из слов собраны хедеры встроенных типов, данные которых лежат в другом месте памяти:

  • строка – два слова: указатель на массив байт и длина;
  • слайс – три слова: указатель на массив, длина и капасити;
  • интерфейсное значение – два слова: указатель на itab (у пустого интерфейса – на тип) и указатель на данные.
Встроенные типы Go в машинных словахСверху – две линейки байт шириной в три машинных слова: по 8 байт в слове на amd64 и arm64, по 4 байта на 386 и arm. Ниже – полосы из слов той же ширины: int – одно слово-число, *int – одно слово-указатель, string – два слова (ptr и len), any – два слова-указателя (type и data), []int – три слова (ptr, len и cap). В словах размеры одинаковы на всех платформах, в байтах – зависят от размера слова. слово слово – 8 байтamd64, arm64 слово – 4 байта386, arm 42int1 слово ptr*int1 слово ptr lenstring2 слова type dataany2 слова ptr len cap[]int3 словауказательчисло

Размер хедера не зависит от данных: строка из миллиона байт занимает те же два слова, что и пустая. Поэтому, когда строку, слайс или интерфейс передают в функцию, копируются только эти слова, а не сами данные.

Размер значения в байтах возвращает unsafe.Sizeof:

package machineword

import (
	"fmt"
	"unsafe"
)

func PrintSizes() {
	var (
		n     int
		p     *int
		s     string
		i     any
		slice []int
	)

	fmt.Printf("int:    %d\n", unsafe.Sizeof(n))
	fmt.Printf("*int:   %d\n", unsafe.Sizeof(p))
	fmt.Printf("string: %d\n", unsafe.Sizeof(s))
	fmt.Printf("any:    %d\n", unsafe.Sizeof(i))
	fmt.Printf("[]int:  %d\n", unsafe.Sizeof(slice))
}
go

На 64-битной платформе (amd64, arm64) PrintSizes выведет:

int:    8
*int:   8
string: 16
any:    16
[]int:  24

На 32-битной платформе (386, arm) каждое число вдвое меньше.

Подробнее о том, что хранят эти хедеры, – в статьях Строки в Go, Слайсы в Go и Интерфейсы в Go.