In Rust probeert de compiler gegevens efficiënt in het geheugen te plaatsen, gebruikmakend van kennis over uitlijning en lay-outmogelijkheden van structuren en enum's. Deze vraag is bijzonder relevant in laag-niveau en systeemontwikkeling, wanneer een overbodige typegrootte leidt tot significante verspilling van geheugen.
Automatische uitlijning van structuren is een kenmerk van de meeste talen, echter in Rust biedt de compiler strikte garanties over de lay-out (met de mogelijkheid tot optimalisatie), en in het geval van enum's wordt compacte opslag gerealiseerd door het combineren van geheugen voor alle varianten, rekening houdend met de maximale grootte).
De volgorde en types van velden in een structuur of enum beïnvloeden de uiteindelijke grootte van het type vanwege de uitlijningspecifieke kenmerken. Een onjuiste volgorde vergroot de "padding" — ongebruikte bytes. Bij enum's met geassocieerde gegevens bepaalt de maximale variant de grootte, en sommige constructies kunnen een enum onvoorzien omvangrijk maken.
Geef de volgorde van velden correct aan en kies types zorgvuldig, analyseer de grootte van gegevens via std::mem::size_of. Voor enum's — wees voorzichtig met geneste structuren en pointers.
Codevoorbeeld:
struct Bad { a: u8, // gebruikt 1 byte + 7 bytes padding b: u64, // gebruikt 8 bytes } struct Good { b: u64, // 8 bytes, uitlijning vanaf het begin a: u8, // 1 byte + 7 bytes padding aan het einde }
Groottecontrole:
use std::mem::size_of; println!("{}", size_of::<Bad>()); // 16 bytes println!("{}", size_of::<Good>()); // 16 bytes (maar padding nu aan het einde)
Voor enum:
enum Example { Unit, Num(u32), Pair(u64, u8), } println!("{}", size_of::<Example>()); // grootte — max(grootte varianten) + discriminant
Belangrijke kenmerken:
Als je de velden u8 en u64 in de structuur verwisselt, verandert de grootte van de structuur?
Nee, de totale grootte blijft een veelvoud van de uitlijning van het grootste veld, maar de padding verschuift. Dit is belangrijk als de structuur wordt opgenomen in een andere structuur of wordt doorgegeven aan FFI.
Kan een kleine enum een grote geheugengrootte hebben?
Ja, als ten minste één variant een groot object of een verwijzing bevat, zal de totale grootte van de enum overeenkomen met de "zwaarste" variant plus discriminant.
Is de lay-out van een structuur altijd hetzelfde op alle platforms?
Nee, lay-out en uitlijning kunnen verschillen tussen architecturen. Voor strikte controle worden de attribuut repr(C) gebruikt.
#[repr(C)] struct MyFFIStruct { x: u32, y: u8, }
In grote verzamelingen wordt een enum met een geneste Vec gebruikt, wat zelden voorkomt, maar de grootte van de enum met een factor 10 vergroot. Geheugen wordt verspild.
Voordelen:
Nadelen:
De enum wordt verdeeld in verschillende kleinere enum's, arrays/verzamelingen worden apart opgeslagen of via Box voor zeldzame varianten, de lay-out wordt gecontroleerd via #[repr(C)]. De grootte is gecontroleerd via size_of.
Voordelen:
Nadelen: