W C/C++ i innych niskopoziomowych językach programista musi jawnie zarządzać umiejscowieniem danych w pamięci: na stosie (zmienne automatyczne) lub w stercie (alokacja przez malloc/new). W tych językach często pojawiają się błędy związane z wyciekami pamięci, podwójnym zwolnieniem lub używaniem nieinicializowanej lub już usuniętej pamięci. Rust przyjmuje odpowiedzialność za ścisłą kontrolę pamięci za pomocą systemu własności, bez używania zbieracza śmieci.
Automatyczne zarządzanie pamięcią przez stos jest wygodne, ale ograniczone rozmiarami (głębokością stosu). Alokacja w stercie wymaga jawnego zarządzania zasobami, co jest niebezpieczne: można zapomnieć o zwolnieniu pamięci lub naruszyć obszary życia wskaźników. Zbieracz śmieci – nie zawsze jest rozwiązaniem (koszty zasobów, nieprzewidywalne przerwy). Błędy zarządzania pamięcią prowadzą do awarii i luk bezpieczeństwa.
W Rust stos i sterta różnią się automatycznym zarządzaniem: wszystkie wartości domyślnie są umieszczane na stosie, a dla obiektów o dynamicznych rozmiarach lub długożyjących używa się sterty przez inteligentne wskaźniki (np. Box<T>, Vec<T>). System własności i pożyczek gwarantuje, że po przekazaniu własności lub zakończeniu obszaru życia zasoby zostaną automatycznie zwolnione. Wszystko to zapewnia gwarantowane bezpieczeństwo na etapie kompilacji i brak zbędnych przerw od zbieracza śmieci.
Przykład kodu:
fn main() { let a = 42; // alokacja na stosie let b = Box::new(42); // alokacja w stercie let mut v = Vec::new(); v.push(1); v.push(2); // dane tablicy w stercie }
Kluczowe cechy:
Czy można ręcznie zwolnić (drop) pamięć na stosie?
Nie. Zwolnienie zmiennych zaalokowanych na stosie odbywa się automatycznie przy wyjściu z obszaru widoczności, ręczne wykonywanie drop jest bezużyteczne, a nawet niedopuszczalne dla wskaźników stack.
Czy przenoszenie (move) powoduje przeniesienie na stertę?
Nie. Przenoszenie zmiennej między właścicielami niekoniecznie przenosi ją na stertę, zmienia się tylko własność.
Czy użycie Box<T> gwarantuje, że T zawsze jest w stercie?
Tak, Box<T> rzeczywiście alokuje T w stercie, jednak własność i obszar życia są nadal ściśle kontrolowane.
W projekcie używane są globalne wektory (Vec<T>) z ręczną realizacją czyszczenia przez mem::forget lub drop, czasami pozostawiając wiszące wskaźniki do usuniętej pamięci.
Zalety:
Wady:
Obiekty są wyraźnie umieszczane przez Box, transfer danych odbywa się zgodnie z zasadą własności, dla kolekcji używa się inteligentnych wskaźników i nie zwraca się referencji do zmiennych stack.
Zalety:
Wady: