Стендап Сьогодні 📢 Канал в Telegram @stendap_sogodni
🤖🚫 AI-free content. This post is 100% written by a human, as is everything on my blog. Enjoy!05.09.2023
Вирівнювання структур в Go
На роботі поділилися цікавою статтею. У двох словах: Golang вирівнює кожний елемент структури так, що він розташовується в памʼяті на межі, кратній його розміру (наприклад, int64
- на адресі, що кратна 8 байтам.) Таким чином, якщо в структурі перемішані поля byte
та int64
, можна витратити набагато більше памʼяті, ніж очікуєш (а byte
використовують, щоб заощадити памʼять, чи не так?)
Нащо це робиться? Бо це прискорює доступ на самому базовому рівні, тобто читання даних з оперативної памʼяті до регістрів процесора. Така оптимізація не втратила своєї актуальності й досі. Без вирівнювання можна отримати в рази гірший час виконання. А деякі інструкції процесора взагалі обовʼязково вимагають вирівнювання. Гарне детальне пояснення є тут.
Та, мова Go достатньо абстрагована, щоб робити вирівнювання автоматично. Для порівняння, на C структура є буквально відображенням області памʼяті на набір полів, тому ніякого вирівнювання не відбувається та ми вільні власноруч обирати, де розташовується кожне поле — навіть якщо це означає стріляти собі в ногу.
Залишається питання — чому тоді Go не оптимізує порядок полів також для економії пам’яті? Я знайшов відповідь — це просто складно. Є пара обговорень конкретно про це. Поки що навіть з автоматичним вирівнюванням є багато нюансів.
Зате існують напівавтоматичні інструменти: правило fieldalignment
для govet
- його треба явно увімкнути в golangci-lint. Та оптимізатор gopium. Я спробував fieldalignment
на нашому проєкті — він знайшов купу “покращень” - але в більшості випадків я б віддав перевагу осмисленій послідовності полів, а не перемішаній заради оптимізації. Хіба що якщо це структура для внутрішньої бази даних, що зберігатиме тисячі записів.