Posted by
oleksii on
1/31/2012 10:59 PM |
Comments (0)
People say generic collections offer a lot of benefits compared to the non-generic ones. This post is a short reminder to myself (mostly) as of what are those benefits.
1 Memory usage
I start with a few lines of code in C#4, all pretty basic stuff. I ran it in Debug mode and waited till debugger stopped at the last line of main method. Then I got Immediate Window (in Visual Studio) opened, loaded SOS extension and dumped all the objects' sizes. Below is the code and in comments I put the extracted sizes of objects.
==Immediate Window==
.load sos
!ObjSize
==Code==
int count = 1000;
var arrayList = new ArrayList(count); //4040 bytes
var byteList = new List<byte>(count); //1036 bytes
var stack = new Stack(count); //4040 bytes
var genericStack = new Stack<byte>(count); //1036 bytes
var queue = new Queue(count); //4052 bytes
var genericQueue = new Queue<byte>(count); //1044 bytes
Apparently, this is all platform, CLR (pointers on 32-bit and 64-bit machines are different and different versions can use updated code), hardware etc etc dependent, but to me it's enough to see a generic collection use much less memory with value types. Overheat for storing boxed objects is quite large (nearly 4 times in this sample!).
2 Performance
I tested adding and taking 10.000.000 items into generic and non-generic collections. Here's a snippet of code and the results.
class Program
{
static Random r = new Random();
static void Main(string[] args)
{
//Init
int count = 10000000;
byte[] values = new byte[count];
r.NextBytes(values);
var arrayList = new ArrayList(count);
var byteList = new List<byte>(count);
//...
//Timed stress-load: add then take
var arrayListTime = TimeAction(() =>
{
for (int i = 0; i < values.Length; i++)
{
var value = values[i];
arrayList.Add(value);
}
for (int i = 0; i < values.Length; i++)
{
var value = values[i];
int k = (byte)arrayList[i];
}
});
//...
//Output results
Console.WriteLine("array list: " + arrayListTime);
//...
}
private static TimeSpan TimeAction(Action action)
{
var sw = new Stopwatch();
sw.Start();
action.Invoke();
sw.Stop();
return sw.Elapsed;
}
}
And the output is
-----------------------------
-----------------------------
array list: 2.2440829 sec
generic list: 0.2694271 sec
-----------------------------
stack: 2.0472536 sec
generic stack: 0.3369304 sec
-----------------------------
queue: 1.9683970 sec
generic queue: 0.3751191 sec
-----------------------------
-----------------------------
It can be clearly seen that generics outperform non-generic collections. The time gain happens because generic collection doesn't spend time on boxing/unboxing and subsequent copy of the value to the value-type location.
3 Clean code
Consider a situation where one developer thinks he works with fruits, but somebody else has made an error and used an incorrect type.
stack.Push(new Apple());
stack.Push(new Dog());
var item = stack.Pop();
//you cannot peel a dog
//but guess when you learn this?
((Fruit)item).Peel();
4 Variance
Generic classes are invariant in .NET2 - .NET4 inclusive. However in .NET 4 delegates and interface got support for one-directional variance (via either in or out keywords). Because it's a big topic I shall stop here and refer the reader to thoughts on stackoverflow and msdn.
5 Limitations
Generics support only classes, structs,interfaces, delegates and methods. It's not possible to parametrize events, constructors, properties, indexers etc.
Performance gain is not noticeable for reference type's collections (as boxing/unboxing/copying does occur) and for single parametrized item (as it's just too quick to make an effect).
If you enjoyed this post, make sure you subscribe to my RSS feed!
f0fe4163-cc64-41b6-9c76-8c79140de11f|0|.0