About the author

Miron Abramson
Me
Software Engineer,
CTO at PixeliT
and .NET addicted for long time.
Open source projects:
MbCompression - Compression library

Recent comments

Authors

Disclaimer

The opinions expressed herein are my own personal opinions and do not represent my employer's view in anyway.

© Copyright 2014

Creative Commons License

Blog Flux Directory
Technology Blogs - Blog Top Sites

Fast version of the Activator.CreateInstance method using IL

We all know (I guess) the method Activator.CreateInstance(Type) and the generic version:  Activator.CreateInstance<T>()  that are used to create an instance of a specified Type.

In now days all are talking about 'Entity-relationship model' , 'Object-relational mapping' and that stuff, that basically it means getting a IDataReader, loop over it and fill with the data a List with specfied type of objects and return a List instead of DataSet or DataTable (or similar mechanism). While looping over the IDataReader, every iterate, an instance of the specified type needs to be create. It can be done using one of the methods above, but it can be improved by usind IL and some help using some cache. Here is how can it be done:

public static class FastObjectFactory
{
    private static readonly Hashtable creatorCache = Hashtable.Synchronized(new Hashtable());
    private readonly static Type coType = typeof(CreateObject);
    public delegate object CreateObject();

    /// <summary>
    /// Create an object that will used as a 'factory' to the specified type T 
   /// <returns></returns>
    public static CreateObject CreateObjectFactory<T>() where T : class
    {
        Type t = typeof(T);
        FastObjectFactory.CreateObject c = creatorCache[t] as FastObjectFactory.CreateObject;
        if (c == null)
        {
            lock (creatorCache.SyncRoot)
            {
                c = creatorCache[t] as FastObjectFactory.CreateObject;
                if (c != null)
                {
                    return c;
                }
                DynamicMethod dynMethod = new DynamicMethod("DM$OBJ_FACTORY_" + t.Name, typeof(object), null, t);
                ILGenerator ilGen = dynMethod.GetILGenerator();

                ilGen.Emit(OpCodes.Newobj, t.GetConstructor(Type.EmptyTypes));
                ilGen.Emit(OpCodes.Ret);
                c = (CreateObject)dynMethod.CreateDelegate(coType);
                creatorCache.Add(t, c);
            }
        }
        return c;
    }
}

Note the static HashTable is been used as a cache. The first  time we create a delegate 'CreateObjec' for the given type it is 'slow', so all the point here, is to cache this delegate. The next time we need to create an object from the given type, the 'CreateObjec' delegate will be used from the cache. Without caching it, the whole story worth nothing.

Here are some benchmarks:

1 Object:



100 Objects:

1000 Objects:

Comparing to the generic constraint : new()

Below there is the small project I used for the benchmarks:

FastObjectFactory.zip (50.35 kb)

Currently rated 5.0 by 6 people

  • Currently 5/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Categories: C# | Performance | IL
Posted by Miron on Saturday, August 09, 2008 12:52 PM
Permalink | Comments (19) | Post RSSRSS comment feed

Related posts

Comments

m goode us

Monday, November 17, 2008 8:10 AM

m goode

Can this command be used on the Motorola Krave? I would love to see if it could! I became a big fan of the krave not too long after I started working with Motorola. Has anyone seen the features online? (motorola.com/krave) My favorites are the 2 MP camera and touch screen. It's definitely worth checking out.

Damien McGivern gb

Sunday, November 23, 2008 9:50 PM

Damien McGivern

Hi,

I'm just wondering why you don't use the generic constraint : new() which would require the type being created has a constructor with no parameters, as this is what the generated IL code is looking for, this way you're not using reflection at all.

Damien

Miron il

Sunday, November 23, 2008 11:22 PM

Miron

@Damien,
Can you give an example for what your mean?

Damien McGivern gb

Monday, November 24, 2008 1:13 AM

Damien McGivern

see http://msdn.microsoft.com/en-us/library/sd2w2ew5(VS.80).aspx

example

class ItemFactory<T> where T : new()
{
public T GetNewItem()
{
return new T();
}
}

Miron il

Monday, November 24, 2008 8:53 AM

Miron

@Damien,
Thats will be exactly the same as Activator.CreateInstance<T>() (even worse performance)
The point is using IL to improve the object creating performance.

Damien McGivern gb

Monday, November 24, 2008 11:37 AM

Damien McGivern

Miron, you're incorrect. Activator.CreateInstance<T> may look like the example I gave earlier but Activator.CreateInstance<T> doesn't use the generic new() constraint meaning it has to use reflection to create the object. Generics doesn’t use reflection at all, instead it simple won't let you compile code that doesn't follow its rules - this is why in the background the generic code can call the constructor directly as it's guaranteed to be there. To prove my point run the code below and you'll see that using the new() constraint is about a quarter faster that the IL and it has the added bonus of being type safe and not requiring a cast.

On my laptop the example below results in timings of 0.0159353 and 0.0202851 for the new() constraint and the IL code respectively.



using System;
using System.Collections;
using System.Diagnostics;
using System.Reflection.Emit;

namespace ConsoleApplication1
{
internal class Program
{
private static void Main(string[] args)
{
const int max = 9999;

var sw = new Stopwatch();



Console.WriteLine("Generic new constraint"Wink;
sw.Start();
var factory1 = new ItemFactory<Test>();
for (int i = 0; i < max; i++)
{
Test f = factory1.GetNewItem();
}
sw.Stop();

Console.WriteLine(sw.Elapsed);


Console.WriteLine("IL code"Wink;
sw.Start();
FastObjectFactory.CreateObject factory2 = FastObjectFactory.CreateObjectFactory<Test>();
for (int i = 0; i < max; i++)
{
var g = (Test) factory2();
}
sw.Stop();

Console.WriteLine(sw.Elapsed);

Console.Read();
}

#region Nested type: FastObjectFactory

public static class FastObjectFactory
{
#region Delegates

public delegate object CreateObject();

#endregion

private static readonly Type coType = typeof (CreateObject);
private static readonly Hashtable creatorCache = Hashtable.Synchronized(new Hashtable());

/// <summary>
/// Create an object that will used as a 'factory' to the specified type T
/// <returns></returns>
public static CreateObject CreateObjectFactory<T>() where T : class
{
Type t = typeof (T);
var c = creatorCache[t] as CreateObject;
if (c == null)
{
lock (creatorCache.SyncRoot)
{
c = creatorCache[t] as CreateObject;
if (c != null)
{
return c;
}
var dynMethod = new DynamicMethod("DM$OBJ_FACTORY_" + t.Name, typeof (object), null, t);
ILGenerator ilGen = dynMethod.GetILGenerator();

ilGen.Emit(OpCodes.Newobj, t.GetConstructor(Type.EmptyTypes));
ilGen.Emit(OpCodes.Ret);
c = (CreateObject) dynMethod.CreateDelegate(coType);
creatorCache.Add(t, c);
}
}
return c;
}
}

#endregion

#region Nested type: ItemFactory

private class ItemFactory<T> where T : new()
{
public T GetNewItem()
{
return new T();
}
}

#endregion

#region Nested type: Test

private class Test
{
}

#endregion
}
}

Miron il

Monday, November 24, 2008 12:24 PM

Miron

@Damien,
You missed the most important part in your benchmark- caching the 'CreateObject ' object. The first time will be slow (of-course) but since it is in the cache - it will be much faster than any other 'Object factory'.
Also, I attached screen shot of benchmark with the generic constrain new(), and surprisingly , it is even slower than Activator.CreateInstance<T>() and much slower than the IL code - after it was cached.
You can download the source code - it include the whole benchmarks code.

Damien McGivern gb

Monday, November 24, 2008 10:42 PM

Damien McGivern

@Miron I stand corrected, the IL code is much faster than the generic new() constraint. My test benchmark code wasn't calling the Reset on the stopwatch, D'oh - that'll teach me to post late night code.

We use the new() constraint in a key part of some code at work. We cache the reflection code for populating our business objects but not their creation, after this exchange we will be now.

Although I've rewritten this code so that it no longer requires caching, locking, casting and is type safe at compile time:


public static class FastObjectFactory2<T> where T : class, new()
{
public static Func<T> CreateObject{get; private set;}

static FastObjectFactory2()
{
Type objType = typeof(T);
var dynMethod = new DynamicMethod("DM$OBJ_FACTORY_" + objType.Name, objType, null, objType);
ILGenerator ilGen = dynMethod.GetILGenerator();
ilGen.Emit(OpCodes.Newobj, objType.GetConstructor(Type.EmptyTypes));
ilGen.Emit(OpCodes.Ret);
CreateObject = (Func<T>WinkdynMethod.CreateDelegate(typeof(Func<T>Wink);
}
}

Moving the generic parameter from the method to the type creates a unique factory type for each object type we are trying to create. This means we can make the delegate static. So we move the IL method creation into the factory static constructor meaning it is only ever called once. I've added the generic new() constraint although I don't use this to create the object it does ensures that there is a public constructor with no parameters at compile time making the code that bit more safe. I’ve also exposed the generic type in the creation delegate removing the need to cast. With these improvements you get an increase in performance over the original IL code and cleaner code.


watch = Stopwatch.StartNew();
var create3 = FastObjectFactory2<MyObject>.CreateObject;
for (int i = 0; i < MAX; i++)
{
MyObject myObj = create3();

}


What do you think?

Miron il

Monday, November 24, 2008 11:22 PM

Miron

@Damien,
You got it Damien!
Very nice and clean code indeed. Smile
Even that your code gives the same performance as my original IL code (even when using the casting), it is cleaner
and more important - it is type safe.
I will update our code too!
Thanks

m goode us

Tuesday, November 25, 2008 7:39 AM

m goode

I like this code. Does anyone know how programming languages work for cell phones? I'm interested to see how technology for touch screens work. I've been working with Motorola recently and have became a huge fan of the Krave. I love the touch screen functionality and 2 MP camera. It's incredible! Check it out online at Motorola.com/krave.

Damon Wilder Carr us

Thursday, November 27, 2008 8:17 AM

Damon Wilder Carr

Don't get me wrong here... I love geeky performance tweaks.. But are you saying this was a 'fix' for a showstopper performance problem for any known application now or ever previously created on the .NET platform? Is this in any way solving a problem that merits the added complexity introduced? In my world I am measured on the fact that 80% of software budgets go to maintenance, not new dev, and performance optimization is verbotten until there is a darn good reason to bring it up.

It is was, I would tend to thing many nastier things are at work then a simple newobj opcode.

Damon

P.S. Why not write a language? Then you can use compiler optimizations and constructs you introduce to optimize every last cycle? I'm not even being sarcastic. Have you used Boo? Amazing stuff.... DSLs are the future in a big way I believe which we already see in Linq providers.

Miron il

Thursday, November 27, 2008 8:26 AM

Miron

@Demon,
What up with you man? Are you a philosopher ?
What are you talking about ?

Damon Wilder Carr us

Monday, December 08, 2008 1:57 AM

Damon Wilder Carr

Miron,

Actually.. If I had another job that would be it.. But no I'm just a coder like you. I've been burned so many times by premature optimization and managing complexity injected for no good reason (which is most of what we end up doing as coders).

Like I said, it's a good post, but I constantly am leading teams and having to explain why it makes no sense to optimize first.

Damon

Greg us

Wednesday, December 17, 2008 5:22 AM

Greg

Silly question here:
using your great example, how could I pass params object[] args to an expecting constructor?
Could I be approaching this wrong if I need to instantiate a class with arguments?

Please advise.

Also, great examples by Miron and Damien.
Thanks

Miron il

Sunday, December 21, 2008 10:08 AM

Miron

@Greg,
I guess it can be done.
Some modifications in the code are needed, of course.
I will be glad to get some benchmarks results for that Smile

Luke us

Monday, October 12, 2009 5:38 AM

Luke

Please forgive me, I do realize that this post is rather old...

I have been programming in .NET off and on for about 6 years now, definitely not a pro and don't have quite the amount of time to really dive in as deep as I want to be. I have a strong interest in shifting my career to .NET development and I am currently working on a networking library that will require a lot of packets to be created on the fly as data is read off the socket.

My question is what would the benefits be with this method vs. a direct call since this method requires a class to be passed in the T parameter? Since a class must be specified, it is essentially the same thing as a direct call, unless I'm just not seeing something. My library registers packets to a dictionary and it would not be friendly to have to hard code a switch statement to switch on the different types of packets, not to mention anyone utilizing the library wouldn't be able to define their own packets with the hard coded switch statement method. It is far easier to pass in the packet Type to Activator.CreateInstance, which I know is slower than your method here.

I made a really small modification to your code here (removing generics) and made it able to pass in Types instead of the class. There are a couple of things I am trying to figure out. Damien's code is clean and does not require a cache because the IL is compiled at compile time. Using the Type method, I don't think that is possible to do, unless I'm overlooking something. Another thing is that performance is only marginally better than Activator when I have to call to the CreateObjectFactory to create a new object each time new data comes in off the socket. I'm not able to create a delegate variable and store the returned delegate from CreateObjectFactory since there are many different types of packets.

Here is the code using the "Type" method:

public static CreateObject CreateObjectFactory(Type type)
{
FastObjectFactory.CreateObject c = creatorCache[type] as FastObjectFactory.CreateObject;
if (c == null)
{
lock (creatorCache.SyncRoot)
{
c = creatorCache[type] as FastObjectFactory.CreateObject;
if (c != null)
{
return c;
}
DynamicMethod dynMethod = new DynamicMethod("DM$OBJ_FACTORY_" + type.Name, typeof(object), null, type);
ILGenerator ilGen = dynMethod.GetILGenerator();

ilGen.Emit(OpCodes.Newobj, type.GetConstructor(Type.EmptyTypes));
ilGen.Emit(OpCodes.Ret);
c = (CreateObject)dynMethod.CreateDelegate(coType);
creatorCache.Add(type, c);
}
}
return c;
}

Any suggestions?

Chris us

Monday, January 11, 2010 4:26 AM

Chris

Hey, I started a StackOverflow.com question on the above post wanting to find out what would be the best way to create a fast Activator for classes that require params. I'm hoping that you would get in on the conversation as well.
stackoverflow.com/.../how-to-pass-ctor-args-in-activator-createinstance

glass.lu

Saturday, September 17, 2011 2:10 AM

pingback

Pingback from glass.lu

Improving Performance » Glass

muibiencarlota.wordpress.com

Thursday, April 11, 2013 9:34 PM

pingback

Pingback from muibiencarlota.wordpress.com

Fast version of the Activator.CreateInstance method using IL | Around computing