Стендап Сьогодні 📢 Канал в Telegram @stendap_sogodni

🤖🚫 Контент вільний від AI. Цей пост на 100% написаний людиною, як і все на моєму блозі. Насолоджуйтесь!

05.09.2023

Вирівнювання структур в Go

На роботі поділилися цікавою статтею. У двох словах: Golang вирівнює кожний елемент структури так, що він розташовується в памʼяті на межі, кратній його розміру (наприклад, int64 - на адресі, що кратна 8 байтам.) Таким чином, якщо в структурі перемішані поля byte та int64, можна витратити набагато більше памʼяті, ніж очікуєш (а byte використовують, щоб заощадити памʼять, чи не так?)

Нащо це робиться? Бо це прискорює доступ на самому базовому рівні, тобто читання даних з оперативної памʼяті до регістрів процесора. Така оптимізація не втратила своєї актуальності й досі. Без вирівнювання можна отримати в рази гірший час виконання. А деякі інструкції процесора взагалі обовʼязково вимагають вирівнювання. Гарне детальне пояснення є тут.

Та, мова Go достатньо абстрагована, щоб робити вирівнювання автоматично. Для порівняння, на C структура є буквально відображенням області памʼяті на набір полів, тому ніякого вирівнювання не відбувається та ми вільні власноруч обирати, де розташовується кожне поле — навіть якщо це означає стріляти собі в ногу.

Залишається питання — чому тоді Go не оптимізує порядок полів також для економії пам’яті? Я знайшов відповідь — це просто складно. Є пара обговорень конкретно про це. Поки що навіть з автоматичним вирівнюванням є багато нюансів.

Зате існують напівавтоматичні інструменти: правило fieldalignment для govet - його треба явно увімкнути в golangci-lint. Та оптимізатор gopium. Я спробував fieldalignment на нашому проєкті — він знайшов купу “покращень” - але в більшості випадків я б віддав перевагу осмисленій послідовності полів, а не перемішаній заради оптимізації. Хіба що якщо це структура для внутрішньої бази даних, що зберігатиме тисячі записів.