Vec<T> — dinamik, büyüyen bir dizi olup, elemanları tek bir tahsis edilmiş (heap'te) bellek bloğunda saklar. Yeni bir eleman eklemek (push) uzunluğu artırır, gerekirse yeni bellek tahsis edilir (realloc). Push işlemi sırasında, sürekli yeniden tahsisatlardan kaçınmak için, capacity üssel olarak artırılır. Bir eleman silindiğinde (pop/remove) capacity otomatik olarak azalmaz.
Sık karşılaşılan bir problem — sürekli ekleme yapıldığında aşırı tahsisatlar ve yeniden tahsisat yapılmasıdır.
Önceden tahsisle çalışma örneği:
let mut v = Vec::with_capacity(1000); for i in 0..1000 { v.push(i); } assert_eq!(v.capacity(), 1000);
Soru: v.shrink_to_fit() çağrıldıktan sonra vec'in capacity'si ne olacak? Uzunluğa tam olarak eşit olacak mı?
Yanlış cevap: Evet, her zaman, shrink_to_fit'ten sonra capacity == len.
Doğru cevap: Mutlaka değil, shrink_to_fit'in uygulanması tahsisöğretmene bir "istek" olarak değerlendirilir. Genellikle mümkün olan en düşük kapasiteye ulaşmaya çalışır, tahsisçiye göre farklılıklar olabilir (örneğin, uzunluktan yüksek kalabilir).
Örnek:
let mut v = Vec::with_capacity(10); for i in 0..5 { v.push(i); } v.shrink_to_fit(); // capacity ≥ len (5), ama == len olduğundan emin değiliz
Hikaye
Geliştirici, kapasite belirtmeden sıkça objeleri Vec'e pushtu ve bu da büyük veri boyutlarında yeniden tahsisatların üssel olarak artmasına neden oldu, bu da "ağır" döngülerde tüm işlemeyi yavaşlattı.
with_capacityile yapılan optimizasyon zamanı 10 kat azalttı.
Hikaye
Ekibin, her pop'tan sonra düzenli olarak
shrink_to_fitçağrısı yaparak bellek tasarrufu sağlamaya çalışması sonucunda sürekli yeniden tahsisat/free döngüleri ve performans düşüşü ortaya çıktı, hizmeti neredeyse DoS'a sürükledi.
Hikaye
Struct içinde elemanlarına iç referanslar olan bir Vec bırakıldı. Kapasiteden fazla push yapıldığında (realloc) referanslar geçersiz hale geldi — ortaya çıkan hataları üretime geçmeden önce hesaplamak zordu.