Vec<T> è un array dinamico, growable, che memorizza gli elementi in un unico blocco di memoria allocato (nel heap). Aggiungere un nuovo elemento (push) aumenta la lunghezza e, se necessario, è stata allocata nuova memoria (riallocazione). Durante il push aumenta la capacity in modo esponenziale per evitare riallocazioni costanti. Quando si rimuove un elemento (pop/remove) la capacity non diminuisce automaticamente.
Un problema comune è la sovrallocazione e la riallocazione durante l'aggiunta costante.
Esempio di lavoro con allocazione preventiva:
let mut v = Vec::with_capacity(1000); for i in 0..1000 { v.push(i); } assert_eq!(v.capacity(), 1000);
Domanda: Cosa succede alla capacity di vec dopo aver chiamato v.shrink_to_fit()? Sarà esattamente uguale alla lunghezza?
Risposta sbagliata: Sì, sempre, dopo shrink_to_fit capacity == len.
Risposta corretta: Non necessariamente, l'implementazione di shrink_to_fit è "un desiderio" per l'allocatore. Di solito cerca di raggiungere la capacity minima possibile, ma possono esserci caratteristiche a seconda dell'implementazione dell'allocatore (ad esempio, potrebbe rimanere superiore alla lunghezza).
Esempio:
let mut v = Vec::with_capacity(10); for i in 0..5 { v.push(i); } v.shrink_to_fit(); // capacity ≥ len (5), ma non è garantito che sia == len
Storia
Uno sviluppatore ha spinto più volte oggetti in Vec senza impostare la capacity, portando a una crescita esponenziale della riallocazione su grandi volumi di dati, rallentando l'intero processo in "cicli pesanti". L'ottimizzazione con
with_capacityha ridotto il tempo di 10 volte.
Storia
Il team ha cercato di risparmiare memoria effettuando regolarmente la chiamata
shrink_to_fitdopo ogni pop(). Di conseguenza, si sono generati cicli di riallocazione/free costanti e deterioramento delle prestazioni, quasi portando il servizio a DoS.
Storia
Hanno lasciato Vec come campo di una struttura con riferimenti interni ai suoi elementi. Dopo la riallocazione (push oltre la capacity) i riferimenti sono stati invalidati - i bug emersi erano difficili da calcolare fino all'esecuzione in produzione.