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

🤖🚫 AI-free content. This post is 100% written by a human, as is everything on my blog. Enjoy!

07.08.2024

Використання памʼяті в Go

Намагаюся знизити розмір величезної структури даних на Golang. (Назвемо її “базою даних в памʼяті.”) Вона більше не влазить в памʼять, відповідно, є сенс знизити витрати, а не просто палити гроші на неоптимально використані ресурси.

Колись я вже дивився на це питання, але тоді питання було більше академічне. На практиці все дуже складно. Звісно, в Go немає способу дізнатися розмір складеної змінної в памʼяті. Майже будь-яка складена змінна буде містити вказівники, тобто складатися з багатьох ділянок памʼяті. Навіть якщо припустити, що всередині немає ані дублікатів, ані циклів вказівників, все одно доведеться рекурсивно збирати все по шматочку.

До того, всі складені типи займають деяку кількість зайвого місця. Структури містять вирівнювальні байти. Масиви мають резервну місткість. З типом map все взагалі погано, бо його нутрощі нам недоступні, та ми практично не можемо дізнатись, яка в словника резервна місткість. Але вона є: дуже грубо кажучи, Go резервує місце під кількість елементів, кратну ступеням двійки.

А зверху того, памʼять виділяється на купі ділянками. Якщо ділянки великі — в них буде багато зайвого місця. Якщо маленькі — каталог ділянок буде сам собою займати забагато. В будь-якому разі реальне використання памʼяті буде ще більше, ніж ми можемо підрахувати за змістом, причому чим більше маленьких обʼєктів — тим гірше. Це ще одна причина уникати зайвих вказівників: кожний вказівник в програмі збільшує фрагментацію памʼяті.

Пишу маленький аналізатор витрат. Поки що мені вдалося “пояснити” десь 60% тих витрат, що повідомляє ReadMemStats. Чи є 40% надлишком на керування памʼяттю? Хочеться, щоб ні.