Reflection and performance
The open source framework Glue that I’ve created, use a lot of reflection to invoke members on objects. This has sparked my interest in exploring the use of reflection in respect to performance. A colleague of mine, Åsmund Eldhuset, and I set aside an evening for a geeknight to get to the bottom of this, and this is what we found out.
There are many ways to use reflection, and the performance on them vary a lot. What we did was to try out every method and timing them to measure performance. These are the methods we tested: Normal property access, normal reflection, compiling and invoking a compiled expression, using Emit to create, compile and run the statement.
Normal property access
To compare the other methods, we measured the performance on accessing a property the normal way:
1 | Run("Normal property access", () => { var city = address.City; }); |
It was no surprise that this was the fastest method.
Normal reflection (250 times slower than normal property access)
1 2 | var cityPropertyInfo = typeof (Address).GetProperty("City"); Run("With reflection", () => cityPropertyInfo.GetValue(address, new object[0])); |
This is what most of us think about when talking about reflection. This is also the by far most common method of reflection used in Glue. Although about 250 times slower than normal property access, this method has very strong sides compared to the other methods.
Invoking compiled expressions (twice as slow as normal property access)
1 2 3 | Expression<Func<Address, string>> expression = x => x.City; var func = expression.Compile(); Run("Invoke compiled expression", () => func.Invoke(address)); |
Using compiled expressions is another way of dynamically invoking members on objects. Due to the syntax exposed in the api in Glue, most mapping specifications enter Glue as (uncompiled) expressions. The fact that it is only about twice as slow than normal property access, is very promising. But there is a catch, a big one. In order to invoke this way, the expression must be compiled. It is not compiled when it enters Glue, so we have to include the time it takes to compile the expression as well.
Compile Expression and invoke it (51700 times slower than normal property access)
1 2 3 4 5 | RunLong("Compile Expression and invoke", () => { var compiledFunction = expression.Compile(); compiledFunction.Invoke(address); }); |
Yes, if you have to compile an expression before invoking it, it takes about 200 times longer to do the operation than with normal reflection. Leaving this a unattractive method to use with Glue.
Using Emit, invoking a compiled expression (4 times slower than normal property access)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | private Func<Address, string> GetEmitDelegate() { var dm = new DynamicMethod("TestMethod", typeof(String), new [] {typeof(Address) }, typeof(Address).Module); MethodInfo getCity = typeof(Address).GetProperty("City").GetGetMethod(); ILGenerator il = dm.GetILGenerator(); il.Emit(OpCodes.Ldarg_0); il.EmitCall(OpCodes.Call, getCity, null); il.Emit(OpCodes.Ret); return (Func<Address, String>)dm.CreateDelegate(typeof(Func<Address, String>)); } var emitDelegate = GetEmitDelegate(); Run("Emit: run compiled statement", ()=>emitDelegate(address)); |
My guess is that using Emit is not something you will be doing a lot. But, we had to try. Again, executing a compiled expression was fast. But as with expressions, the problem comes when you have to compile before running.
Using Emit, create statement, compile it and run (39000 times slower than normal property access)
1 | RunLong("Emit: Create statement, compile, run",()=>Emit(address)); |
As we can see, this is also horribly slow.
Conclusion
Unless you can create an expression/emit statement and compile it and then run the compiled version more than 200 times, in the app’s lifetime, using normal reflection is by far the preferred way to go when you have to dynamically invoke members on objects.
- Tore Vestues
Thanks to Åsmund Eldhuset.


Hey Tore,
Interesting post!
One thing you might want to look at is sort of caching part of the reflection stuff. This is something I do in my CQRS example for the mapping between commands and handlers. The discovery of what to map and such you only do ones and then you create lambda’s that will execute the mapping. This lambda you cache thus removing the need to do the discovery more often. I believe Jeremy removed a lot of reflection.Emit stuff in favor for lambda’s in the later releases as well.
-Mark
July 1st, 2010 at 16:42 (737)You might also take a look at FastReflectionLib http://fastreflectionlib.codeplex.com as you appear to be implementing the same thing. For timings see http://weblogs.asp.net/jeffreyzhao/archive/2009/01/27/fast-reflection-library.aspx
July 1st, 2010 at 17:13 (759)@Mark & @Clinton,
Thanks for the caching advice! I will implement it somehow in Glue.
.Tore
July 2nd, 2010 at 23:33 (023)