Vec::leak¶
Level: reference · for working programmers
One line: Consume the vector and return a slice that outlives it, by never freeing the buffer.
Stable since 1.47.0.
The memory is deliberately not reclaimed. In exchange you get a &'a mut [T] whose lifetime you choose — usually 'static.
The use is a value built once at startup and needed for the whole run: a lookup table computed from configuration, an interned string set. The alternatives are a static (which cannot be computed at runtime in general), OnceLock, or threading an owner through every call — and leak is sometimes simply the clearest of the four.
'static is the common choice, not the required one; a shorter lifetime is legal and just as leaky.
There is no un-leak. Reclaiming means rebuilding a Vec from the raw parts and dropping it, which is unsafe and needs the original capacity — so if you might want the memory back, use into_raw_parts instead, which hands you all three numbers.
Box::leak is the same idea for a single value. And most of the time the honest answer is neither: keep the Vec alive and pass &[T].
Example¶
vec_leak.rs in full — pasted here by tools/run_examples.py from the file CI compiles and runs.
fn main() {
// Consumes the Vec and gives back a mutable slice that outlives it,
// by never freeing the buffer.
let leaked: &'static mut [i32] = vec![1, 2, 3].leak();
leaked[0] = 99;
println!("{leaked:?}");
// It is a slice, so the length is fixed and every slice method works.
leaked.sort();
println!("sorted in place: {leaked:?} first {:?}", leaked.first());
// Why it exists: a value the program builds once at startup and needs for
// the whole run, without a static, a Box::leak dance, or an Rc.
let table: &'static [u8] = vec![0u8, 1, 4, 9, 16].leak();
fn lookup(t: &'static [u8], i: usize) -> u8 { t[i] }
println!("lookup(3) = {}", lookup(table, 3));
// The lifetime is inferred, and 'static is only the most common choice.
// A shorter one is legal and just as leaky.
let short: &mut [u8] = vec![7, 8].leak();
println!("borrowed for less than 'static: {short:?}");
// The memory is NOT freed. If you need it back, reconstruct and drop —
// which is the only way, and it is unsafe.
let v = vec![1u8, 2, 3];
let (ptr, len, cap) = v.into_raw_parts();
let reclaimed = unsafe { Vec::from_raw_parts(ptr, len, cap) };
println!("reclaimed instead of leaked: {reclaimed:?}");
// Box::leak is the same idea for a single value.
let one: &'static mut u32 = Box::leak(Box::new(42));
*one += 1;
println!("Box::leak: {one}");
// And the honest alternative most of the time: keep the Vec alive.
let owned = vec![1, 2, 3];
fn borrow(xs: &[i32]) -> usize { xs.len() }
println!("no leak needed: {}", borrow(&owned));
}
Verified output of vec_leak.rs — regenerated by tools/run_examples.py, never hand-typed.
[99, 2, 3]
sorted in place: [2, 3, 99] first Some(2)
lookup(3) = 9
borrowed for less than 'static: [7, 8]
reclaimed instead of leaked: [1, 2, 3]
Box::leak: 43
no leak needed: 3
See also¶
Vec::into_raw_parts— leak, but keep the receiptVec::into_boxed_slice— the non-leaking owning conversionVec::as_slice— the borrow, when a lifetime will do