In C/C++ e in altri linguaggi a basso livello, il programmatore deve gestire esplicitamente l'allocazione dei dati in memoria: nello stack (variabili automatiche) o nell'heap (allocazione tramite malloc/new). In questi linguaggi si verificano spesso errori di perdite di memoria, doppia liberazione o uso di memoria non inizializzata o già cancellata. Rust si occupa del controllo rigoroso della memoria attraverso un sistema di possesso, senza l'uso di un garbage collector.
La gestione automatica della memoria tramite lo stack è conveniente, ma limitata nelle dimensioni (profondità dello stack). L'allocazione nell'heap richiede una gestione esplicita delle risorse, il che è rischioso: è possibile dimenticare di liberare la memoria o di violare i confini di vita dei puntatori. Il garbage collector non è sempre una soluzione (costi delle risorse, pause imprevedibili). Gli errori nella gestione della memoria portano a crash e vulnerabilità.
In Rust, stack e heap si differenziano per gestione automatica: tutti i valori vengono allocati nello stack per impostazione predefinita, mentre per oggetti di dimensioni dinamiche o a lungo termine si utilizza l'heap tramite puntatori intelligenti (ad esempio, Box<T>, Vec<T>). Il sistema di possesso e prestiti garantisce che dopo il trasferimento di possesso o il termine del ciclo di vita le risorse vengano liberate automaticamente. Tutto ciò offre una sicura garanzia di sicurezza durante la compilazione e l'assenza di pause inutili dal garbage collector.
Esempio di codice:
fn main() { let a = 42; // allocazione nello stack let b = Box::new(42); // allocazione nell'heap let mut v = Vec::new(); v.push(1); v.push(2); // dati dell'array nell'heap }
Caratteristiche chiave:
È possibile liberare manualmente (drop) la memoria nello stack?
No. La liberazione delle variabili allocate nello stack avviene automaticamente al termine del loro ciclo di vita, forzare un drop manuale è inutile e persino inammissibile per i puntatori dello stack.
Il movimento (move) comporta il trasferimento all'heap?
No. Spostare una variabile tra proprietari non implica necessariamente il suo trasferimento nell'heap, cambia solo il possesso.
L'uso di Box<T> garantisce che T sia sempre nell'heap?
Sì, Box<T> effettivamente assegna T nell'heap, tuttavia possesso e ciclo di vita sono comunque controllati rigorosamente.
Nel progetto vengono utilizzati vettori globali (Vec<T>) con una realizzazione manuale della pulizia tramite mem::forget o drop, a volte lasciando puntatori appesi su memoria cancellata.
Vantaggi:
Svantaggi:
Gli oggetti vengono esplicitamente allocati tramite Box, il trasferimento dei dati avviene secondo la regola del possesso, per le collezioni vengono utilizzati puntatori intelligenti e non vengono restituite referenze a variabili allocate nello stack.
Vantaggi:
Svantaggi: