Vec<T> ist ein dynamisches, wachsendes Array, das Elemente in einem zusammenhängenden (auf dem Heap) Allokationsblock speichert. Das Hinzufügen eines neuen Elements (push) erhöht die Länge; bei Bedarf wird neuer Speicher zugewiesen (reallokiert). Bei push erfolgt die Erhöhung der Kapazität exponentiell, um ständige Reallokationen zu vermeiden. Beim Entfernen eines Elements (pop/remove) wird die Kapazität nicht automatisch verringert.
Ein häufiges Problem sind übermäßige Allokationen und Reallokationen bei konstantem Hinzufügen.
Beispiel für die Arbeit mit vorab zugewiesenem Speicher:
let mut v = Vec::with_capacity(1000); for i in 0..1000 { v.push(i); } assert_eq!(v.capacity(), 1000);
Frage: Was passiert mit der Kapazität des vec nach dem Aufruf von v.shrink_to_fit()? Wird sie genau der Länge entsprechen?
Falsche Antwort: Ja, immer, nach shrink_to_fit ist die Kapazität == Länge.
Richtige Antwort: Nicht unbedingt, die Implementierung von shrink_to_fit ist ein "Wunsch" an den Allokator. In der Regel strebt man die minimal mögliche Kapazität an; je nach Implementierung des Allokators können Besonderheiten auftreten (z. B. kann sie über der Länge bleiben).
Beispiel:
let mut v = Vec::with_capacity(10); for i in 0..5 { v.push(i); } v.shrink_to_fit(); // kapazität ≥ len (5), aber es ist nicht garantiert, dass == len
Geschichte
Ein Entwickler hat wiederholt Objekte in Vec gepusht, ohne die Kapazität festzulegen, was zu einem exponentiellen Anstieg der Reallokationen bei großen Datenmengen führte und die gesamte Verarbeitung in "schweren" Schleifen verlangsamte. Die Optimierung mit
with_capacityreduzierte die Zeit um das 10-fache.
Geschichte
Das Team versuchte, Speicher zu sparen, indem regelmäßig
shrink_to_fitnach jedem pop() aufgerufen wurde. Infolgedessen traten Zyklen ständiger Reallokationen/freigaben auf und die Leistung verschlechterte sich, was den Dienst fast zu einem DoS führte.
Geschichte
Der Vec wurde als Feld einer Struktur mit internen Referenzen auf seine Elemente belassen. Nach der Reallokation (push über Kapazität) wurden die Referenzen ungültig — die entstehenden Bugs waren bis zum Start in der Produktion schwer zu diagnostizieren.