В Rust компилятор старается эффективно размещать данные в памяти, используя знания о выравнивании и возможностях layout структур и enum. Вопрос особенно актуален при низкоуровневой и системной разработке, когда избыточный размер типа приводит к существенному перерасходу памяти.
Автоматическое выравнивание структур — особенность большинства языков, однако в Rust компилятор предоставляет строгие гарантии о layout (при этом допускает его оптимизацию), и в случае enum реализует компактное хранение путем объединения памяти под все варианты, учитывая максимальный размер).
Порядок и типы полей в структуре или enum влияют на итоговый размер типа из-за особенностей выравнивания. Неправильный порядок увеличивает "паддинг" — неиспользуемые байты. У enum с ассоциированными данными максимальный вариант определяет размер, а некоторые конструкции могут сделать enum неожиданно громоздким.
Правильно указывать порядок полей и выбирать типы, анализировать размер данных через std::mem::size_of. Для enum — быть аккуратнее с вложенными структурами и указателями.
Пример кода:
struct Bad { a: u8, // занимает 1 байт + 7 байт паддинга b: u64, // занимает 8 байт } struct Good { b: u64, // 8 байт, выравнивание с самого начала a: u8, // 1 байт + 7 байт паддинга в конце }
Проверка размера:
use std::mem::size_of; println!("{}", size_of::<Bad>()); // 16 байт println!("{}", size_of::<Good>()); // 16 байт (но паддинг теперь с конца)
Для enum:
enum Example { Unit, Num(u32), Pair(u64, u8), } println!("{}", size_of::<Example>()); // размер — макс(размер вариантов) + discriminant
Ключевые особенности:
Если переставить поля u8 и u64 в структуре, изменится ли размер структуры?
Нет, общий размер по-прежнему будет кратен выравниванию максимального поля, но паддинг сместится. Это важно, если структура включается в другую структуру или передается в FFI.
Может ли небольшой enum иметь большой размер памяти?
Да, если хотя бы один вариант содержит большой объект или ссылку, общий размер enum будет соответствовать самому "тяжёлому" варианту плюс discriminant.
Одинаков ли layout структуры всегда на всех платформах?
Нет, layout и выравнивание может отличаться между архитектурами. Для строгого контроля используют атрибут repr(C).
#[repr(C)] struct MyFFIStruct { x: u32, y: u8, }
В больших коллекциях используется enum с вложенным Vec, который редко встречается, но увеличивает размер enum в 10 раз. Память расходуется впустую.
Плюсы:
Минусы:
Enum разбит на несколько менее крупных enum, массивы/коллекции хранятся отдельно либо через Box для редких вариантов, layout контролируется через #[repr(C)]. Проверен размер через size_of.
Плюсы:
Минусы: