Добавить в корзинуПозвонить
Найти в Дзене
allaboutknit.ru

Выравнивание в структурах Go: почему байты «ленятся»

Если вы пишете на Go, то наверняка сталкивались с тем, что размер структуры в памяти оказывается больше, чем кажется «на бумаге». Виновато тут выравнивание — невидимый механизм, который делает работу с памятью быстрее, но иногда добавляет лишние байты. Процессор устроен так, что ему удобнее читать данные не по одному байту, а целыми кусками — словами по 4 или 8 байт. Представьте магазин: кассиру удобнее сканировать товары блоками, а не вытаскивать каждую жвачку по одной. Так же и CPU: если данные лежат «красиво» (по границе 4 или 8 байт), доступ к ним происходит быстрее. Возьмём простую структуру: type Example struct {
A int8 // 1 байт
B int32 // 4 байта
C int8 // 1 байт
} Наивный программист думает: 1 + 4 + 1 = 6 байт. Но Go скажет: 12 байт. Почему? Итого: 12 байт вместо ожидаемых 6. Трюк простой: располагайте поля от больших к маленьким. type Better struct {
B int32 // 4 байта
A int8 // 1 байт
C int8 // 1 байт
} Теперь структура займёт 8 байт вместо
Оглавление

Если вы пишете на Go, то наверняка сталкивались с тем, что размер структуры в памяти оказывается больше, чем кажется «на бумаге». Виновато тут выравнивание — невидимый механизм, который делает работу с памятью быстрее, но иногда добавляет лишние байты.

Выравнивание в структурах Go: почему байты «ленятся»
Выравнивание в структурах Go: почему байты «ленятся»

🔧 Что такое выравнивание

Процессор устроен так, что ему удобнее читать данные не по одному байту, а целыми кусками — словами по 4 или 8 байт.

Представьте магазин: кассиру удобнее сканировать товары блоками, а не вытаскивать каждую жвачку по одной. Так же и CPU: если данные лежат «красиво» (по границе 4 или 8 байт), доступ к ним происходит быстрее.

📦 Пример: где теряются байты

Возьмём простую структуру:

type Example struct {
A int8 // 1 байт
B int32 // 4 байта
C int8 // 1 байт
}

Наивный программист думает: 1 + 4 + 1 = 6 байт. Но Go скажет: 12 байт.

Почему?

  • A занимает 1 байт, но следующий int32 должен начинаться с адреса, кратного 4.
  • Значит, между A и B вставляется 3 «пустых» байта (padding).
  • Потом C тоже выравнивается, и Go добавляет ещё 3 байта в конце, чтобы структура делилась на 4.

Итого: 12 байт вместо ожидаемых 6.

Как обойтись без потерь?

Трюк простой: располагайте поля от больших к маленьким.

type Better struct {
B int32 // 4 байта
A int8 // 1 байт
C int8 // 1 байт
}

Теперь структура займёт 8 байт вместо 12.

⚔ Почему это важно

  • В небольших структурах разница кажется смешной.
  • Но если у вас массив из миллиона элементов, то «лишние байты» превращаются в мегабайты памяти.
  • А это уже влияет и на кэш, и на скорость доступа.

🔑 Итог

Выравнивание — это не баг, а особенность работы процессора.

Go заботится о производительности, но программисту стоит помнить:

  • поля стоит упорядочивать по размеру;
  • иногда выгодно использовать struct{} или объединять флаги в uint8;
  • анализировать можно через unsafe.Sizeof() и go vet.

Так что если ваш Go-код вдруг «потолстел» без причины — загляните в выравнивание. Возможно, ваши байты просто ленятся работать.