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.
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.
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
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
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();
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 Software Engineer at Microsoft in the Open Source Programs Office (OSPO), helping Microsoft engineers use, contribute to and release open source at scale.