Course contentsShow
← Rust
Lesson 473 of 1,9104. Lifetimes and Advanced OwnershipFree lesson

Optimizing Collection Growth

Pre-size collections to avoid reallocation during the lifetime of a long-running process.

In this lesson, you will learn how to prevent expensive memory reallocations by pre-sizing your collections before adding data.

The Cost of Dynamic Growth

In Rust, types like Vec<T> or HashMap<K, V> are dynamic; they grow as you add elements. When a collection runs out of pre-allocated capacity, it must perform a "reallocation": it requests a larger block of memory from the system, copies every existing element to the new location, and drops the old memory block.

In a long-running process, if you are filling a collection with thousands of items, doing this incrementally causes the program to stutter as it constantly stops to copy data. This is not just a performance hit; it creates unnecessary memory fragmentation.

Pre-sizing with with_capacity

The most effective way to avoid this is to inform Rust of your needs upfront. If you know how much data you expect to handle, use the with_capacity constructor instead of new.

Consider this example where we expect to process 10,000 log entries:

// Inefficient: Reallocates memory many times as it grows
let mut logs = Vec::new();

// Efficient: Allocates the exact space needed once
let mut logs = Vec::with_capacity(10_000);

for i in 0..10_000 {
    logs.push(format!("Log entry #{}", i));
}

By providing the capacity at initialization, the Vec allocates one contiguous block of memory large enough to hold all 10,000 pointers. The push operations now become simple memory writes rather than complex allocation cycles.

When to Use This

You should reach for with_capacity whenever you have a reasonable estimate of the final size. If you don't know the exact count, even a "best guess" or a "safe upper bound" is often better than the default growth strategy, which can be overly cautious. By minimizing the number of allocations, you reduce the workload on the allocator and keep your application’s memory footprint stable, which is a key principle in building high-performance, predictable systems.

Key Takeaway: Pre-allocating collection capacity eliminates redundant memory copying and stabilizes performance by moving the allocation cost outside of your primary data-processing loop.