Change owners, step through generations, pinning and finalization, or compare memory under load. The model explains concepts; the SDK examples measure real runtime observations.
Open the Memory Lab ↗The memory contract
Count describes how many elements a collection currently contains; Capacity describes how many elements its backing storage can hold before growth is needed. Clearing membership and reducing backing storage are different actions. Reusing capacity can avoid repeated growth allocations, while retaining a very large capacity can increase steady-state memory. A useful choice depends on the expected future workload rather than a universal preference for either clearing or reconstructing every collection. For reference elements, also consider which operations end the collection's references to previously stored objects.
Trace the actual program
The list begins with capacity thirty-two and two integer elements, so its first Count prints 2. Clear changes membership and the next Count prints 0. It does not shrink this list's reserved capacity, so the comparison with thirty-two prints True. TrimExcess is then requested, and the final Count remains 0 because resizing storage is not adding elements. The example deliberately avoids interpreting any capacity change as proof of collection, heap compaction, or a corresponding decrease in the process's memory reported by its operating system.
How the mechanism works
When a List containing references is cleared, it removes those element references from its active storage according to the collection contract, but other owners can still retain the same objects. An integer list has no referenced payload objects in those elements, yet its own backing array is managed storage. Growth generally copies elements to a larger container, which can create temporary allocation pressure. Presizing a known bounded workload may help, but gross overestimation can retain unnecessary storage. Separate membership, element ownership, backing-array lifetime, and external memory metrics when explaining the tradeoff.
Boundaries and misconceptions
Calling TrimExcess after every small operation can create repeated allocation and copy work when the list grows again. Conversely, reusing a one-time enormous capacity indefinitely may be inappropriate for a mostly small workload. Do not infer a precise capacity-growth factor from one runtime and make it a portability requirement. The public contract and a target-specific performance profile are different evidence. A read-only interface also does not make the underlying list immutable or stop its owner from clearing it later.
Practice: change one ownership path
First add a third integer before the initial print and predict Count three, then zero after Clear, with the same minimum-capacity comparison. Hint: the initial reserved storage already has room, but the sample does not count allocations to prove a performance result. Next clear and refill the list several bounded times while checking only logical contents. Verify that each report matches the new batch rather than accidentally including previous elements. Keep the number of repetitions small and deliberate.
Practice: test a second boundary
For a second exercise, store objects and let a separate variable retain one of them before clearing the list. Read it through that owner afterward to show that Clear is not global destruction. Hint: draw the second reference edge. Then compare a reuse policy with a shrink-after-large-batch policy under a measured target workload. Record both allocation churn and retained capacity rather than optimizing one counter blindly, and do not use forced collections to make a process-memory screenshot appear smaller.
Review the evidence
A good collection-memory explanation identifies current items, reserved slots, references to payload objects, and the workload's next expected step. The unchanged output is two, zero, true, and zero. These facts show why a cleared collection can still retain useful backing storage. They do not show a leak by themselves. Decide whether retaining that capacity matches the application's bounds, then validate the chosen reuse or shrinking policy using the correct runtime and a repeatable workload. Check both unusually large batches and ordinary repeated small batches before choosing a retention policy.
- The original membership counts change from two to zero.
- Clear does not shrink the reserved capacity in this example.
- Shrinking and reuse policies should be based on workload evidence.
A working example
using System;
using System.Linq;
using System.Collections.Generic;
using System.Text;
using System.Buffers;
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;
var values = new List<int>(32) { 1, 2 };
Console.WriteLine(values.Count);
values.Clear();
Console.WriteLine(values.Count);
Console.WriteLine(values.Capacity >= 32);
values.TrimExcess();
Console.WriteLine(values.Count);
Expected output
2 0 True 0
The original membership counts change from two to zero.