Skip to content

String::shrink_to_fit

String methods · Strings

Level: reference · for working programmers

One line: Gives back the spare capacity, dropping it to about len() — usually by reallocating and copying.

pub fn shrink_to_fit(&mut self)

Stable since 1.0.0.

It is not free. Shrinking generally means asking the allocator for a smaller block and copying the bytes into it, so calling it in a loop or on a string that will grow again is worse than leaving the slack alone.

The right moment is once, when a string reaches its final size and will be kept for a long time — parsed configuration held for the process lifetime, a million interned names.

The resulting capacity is len() or greater: the allocator is free to keep it larger, and after this the guarantee is only that it is no bigger than before.

For a string that is genuinely finished, into_boxed_str is the stronger move: it shrinks and drops the capacity field entirely, saving eight more bytes per value.

Example

string_shrink_to_fit.rs in full — pasted here by tools/run_examples.py from the file CI compiles and runs.

fn main() {
    let mut s = String::with_capacity(64);
    s.push_str("small");
    println!("before len {} capacity {}", s.len(), s.capacity());

    s.shrink_to_fit();
    println!("after  len {} capacity {}", s.len(), s.capacity());

    // Contents are untouched; only the bookkeeping changed.
    println!("{s:?}");

    // The stronger move for a finished string.
    let mut done = String::with_capacity(64);
    done.push_str("final");
    let boxed = done.into_boxed_str();
    println!("Box<str> is {} bytes vs String's {}",
             std::mem::size_of_val(&boxed), std::mem::size_of::<String>());

    // Shrinking then growing again undoes the saving and costs two copies.
    let mut churn = String::with_capacity(32);
    churn.push_str("ab");
    churn.shrink_to_fit();
    let low = churn.capacity();
    churn.push_str("cdefgh");
    println!("{low} -> {}", churn.capacity());
}

Verified output of string_shrink_to_fit.rs — regenerated by tools/run_examples.py, never hand-typed.

before len 5 capacity 64
after  len 5 capacity 5
"small"
Box<str> is 16 bytes vs String's 24
2 -> 8

See also

String::shrink_to_fit in the standard library ↗

Po polsku

Oddanie zapasu nie jest darmowe: shrink_to_fit zwykle prosi alokator o mniejszy blok i przepisuje do niego bajty, więc wywołanie go w pętli albo na łańcuchu znaków, który zaraz znowu urośnie, kosztuje dwa kopiowania zamiast zera — w przykładzie pojemność (capacity) spada z 32 do 2 i natychmiast wraca do 8. Właściwy moment jest tylko jeden: gdy tekst osiągnął ostateczny rozmiar i będzie trzymany długo — sparsowana konfiguracja żyjąca przez cały czas działania procesu, milion nazw w tablicy symboli. Gwarancja jest przy tym słabsza, niż podpowiada nazwa: wynikowa pojemność to len() albo więcej, bo alokator ma prawo zostawić ją wyższą. A jeśli łańcuch jest naprawdę skończony, mocniejszym ruchem jest into_boxed_str — kasuje samo pole pojemności i zamienia 24 bajty String na 16 bajtów Box<str>.

Szukaj po polsku: pojemność a długość łańcucha znaków · zwalnianie nadmiarowej pamięci · rust String shrink_to_fit · rust into_boxed_str