In this lesson, you will learn how to minimize memory pressure and CPU overhead by explicitly defining collection capacity before populating your data.
The Cost of Dynamic Growth
In C#, dynamic collections like List<T> are backed by an internal array. When you add items beyond the current capacity, the collection must perform a "resize" operation:
- Allocate a new, larger array (typically double the previous size).
- Copy every existing element from the old array to the new one.
- Mark the old array for garbage collection.
If you are adding thousands of items, this cycle repeats multiple times, causing unnecessary CPU cycles for copying and increasing the frequency of Garbage Collection (GC) pressure. By pre-sizing the collection, you ensure a single allocation, allowing the runtime to perform a bulk operation rather than constant "stop-and-copy" cycles.
Implementation Strategy
Whenever you can estimate the final size of a collection—such as when filtering a list or processing a batch of data—always initialize the capacity in the constructor.
// Inefficient: Repeated reallocations as the list grows
var results = new List<ProcessedItem>();
foreach (var item in sourceData)
{
results.Add(Process(item));
}
// Optimized: Pre-sized based on known source data
var results = new List<ProcessedItem>(sourceData.Count);
foreach (var item in sourceData)
{
results.Add(Process(item));
}
When to Pre-Size
You should prioritize pre-sizing in performance-critical paths, such as inside loops that run thousands of times per request or when processing large data sets. If the size is unknown, even a "conservative" estimate (e.g., new List<T>(100)) is often more performant than starting with the default capacity of zero if you know the collection will eventually hold many items.
Beyond List<T>, remember that Dictionary<TKey, TValue> and HashSet<T> are even more sensitive to capacity. Because they require a rehash operation upon resizing, they are significantly more expensive to grow than a List<T>. Providing an initial capacity for these collections can yield substantial performance gains in high-throughput applications.
Key Takeaway: Pre-sizing your collections avoids repeated array allocations and costly data copies, significantly reducing GC pressure and improving application throughput.