Exploring List capacities and growth on the Windows Phone

Posted 17 August 2010  

Since the generic .NET list (List<T> documentation) is a pretty common data structure found in phone apps, I figured it was worth a few minutes to direct everyone’s attention to how the list and its capacity works on the phone.

Unlike desktop computers, where we’re often dealing with gigabytes of potential memory on a modern operating system, the phone has a number of fun and unique memory challenges that managed code developers should be cognizant of.

If you’re using the generic lists in your Windows Phone application, it’s OK to have a bunch sitting around – their default capacity is actually zero until you add items, but you can alter this behavior.

Constructed capacity is ZERO

When you create a new List<T>, the constructed capacity is 0. This means that the cost of creating a new list of pretty minimal, and creating one does not typically allocate any memory for items.

List<string> myList = new List<string>();
// myList.Capacity == 0

I’ve heard of developers who used to think that at construction the list had a large capacity, and that setting an initial size to a few digit number was a performance win. This is often not the case.

First item brings the capacity to 4 items

The first time that you add a single item (or a few), you’ll notice that the capacity size on the Windows Phone will be 4. This is because the internal default number of 4.

List<string> myList = new List<string>();
// myList.Capacity == 0

myList.Add("hello");
// myList.Capacity == 4

You can add 4 items and the capacity will remain at 4.

List<string> myList = new List<string>();
// myList.Capacity == 0

myList.Add("hello");
// myList.Capacity == 4

myList.Add("world!");
// myList.Capacity == 4

myList.Add("bonjour");
// myList.Capacity == 4

myList.Add("le monde!");
// myList.Capacity == 4

Capacity + 1 grows the capacity exponentially

Once the Count == Capacity, it will exponentially grow the capacity. So the capacity will move from 4 to 8 to 16 to 32, 64, 128, 256, … 1024, and so on.

List<string> myList = new List<string>();
// myList.Capacity == 0

myList.Add("hello");
// myList.Capacity == 4

myList.Add("world!");
// myList.Capacity == 4

myList.Add("bonjour");
// myList.Capacity == 4

myList.Add("le monde!");
// myList.Capacity == 4

myList.Add("a fifth item.");
// myList.Capacity == 8

Clipping the capacity back

If you’re in a situation where you’ve added say 500 names from a database, but the capacity is going to be at 1024 at this point, it might be worth clipping back the capacity. Just call the TrimExcess method on the generic list instance.

myList.TrimExcess();

Initializing to a set size

And if you want to keep from potentially re-allocating memory as you add a lot of items, you can always initialize your list to a smart default number that is much larger than 0 or the default capacity of 4 by providing a size in the constructor.

List<string> myList = new List<string>(900);
// myList.Capacity == 900

Note that the capacity will exactly match the number you provide – it won’t jump up to the next exponent or anything like that. Of course it’s possible that behind the scenes the CLR is allocating a specific type of memory on the heap, but as far as numbers exposed to managed code, this is what you get.

Hope this helps.

Jeff Wilcox is a Principal Software Engineer at Microsoft on the Azure team.

Jeff holds a BS in Computer Science from the University of Michigan.

comments powered by Disqus