🧩 Struct Padding: Как вы теряете гигабайты памяти на ровном месте Знаете это чувство, когда вы долго проектируете структуру, высчитываете типы, исполь…
Знаете это чувство, когда вы долго проектируете структуру, высчитываете типы, используете int8 вместо int, чтобы сэкономить память... а потом смотрите в профайлер и плачете?
Вы думаете, что экономите память, а компилятор тихо посмеивается и подкидывает вам мусорные байты.
Проблема в том, что железо читает память не побайтово, а "машинными словами" (обычно по 8 байт на 64-битных архитектурах). Чтобы CPU было удобно и быстро читать данные, компилятор Go выравнивает переменные в памяти, вставляя между ними пустые байты - Padding.
Давайте смотреть на код.
❌ Плохо (Дуршлаг из паддинга):
type BadStruct struct {
a bool // 1 байт
b int64 // 8 байт
c bool // 1 байт
}
Кажется, что размер структуры 1 + 8 + 1 = 10 байт?
По факту: вызов unsafe.Sizeof(BadStruct{}) вернет 24 байта!
Компилятор видит a (1 байт), понимает, что следующий b (8 байт) должен лежать на границе 8 байт, и вставляет 7 байт пустоты. Затем кладет c, и добивает конец структуры еще 7 байтами до ровного числа.
✅ Хорошо (Сортировка от большего к меньшему):
type GoodStruct struct {
b int64 // 8 байт
a bool // 1 байт
c bool // 1 байт
}
Теперь unsafe.Sizeof(GoodStruct{}) равен 16 байтам. Мы сэкономили 33% памяти, просто поменяв строчки местами! А если у вас в in-memory кэше лежат миллионы таких объектов? Это гигабайты сэкономленной RAM на ровном месте.
☝️ Нюансы для Senior-ов:
Не оптимизируйте всё подряд. Если структура создается один раз при старте приложения (например, Config) - забейте. Читаемость и логическая группировка полей важнее. Оптимизируйте только то, что массово аллоцируется, живет в больших слайсах или летает по сети.
Автоматизация. Вам не нужно считать байты в уме. Включите линтер fieldalignment (он есть в составе go vet или golangci-lint). Он сам укажет на проблему сообщением вроде: "struct with 24 pointer bytes could be 16".
#golang #performance #memory #optimization #underhood
👉 @golang_lib