Creating objects - Perf implications
Here are a few examples of how we can create objects, and the perf implications of each way. In all those tests, I have used the following class as my benchmark.
public class Created{public int Num;public string Name;public Created(int num, string name){this.Num = num;this.Name = name;}}
We have a value type and a reference type that are passed to the constructor.
The test code is here:
static void Main(string[] args){int iterations = 1000000;Stopwatch watch = Stopwatch.StartNew();for (int i = 0; i < iterations; i++){CreateInstance(i);}Console.WriteLine(watch.Elapsed);}
Here it my base line, calling the constructor directly.
private static Created CreateInstance(int i){return new Created(i, i.ToString());}
This executes in 00.3648117 seconds on severely underpower laptop. Pretty good, considering we just created a million instances. Now, let us see what happens if we user Activator, shall we?
private static Created CreateInstance(int i){return (Created)Activator.CreateInstance(typeof(Created), i, i.ToString());}
This run depressingly slow, 06.8242636 seconds.
Let us try to improve that a bit, using GetUninitializedObject and directly invoking the constructor.
static ConstructorInfo ctor = typeof(Created).GetConstructors()[0];private static Created CreateInstance(int i){object o = FormatterServices.GetUninitializedObject(typeof(Created));return (Created)ctor.Invoke(o, new object[]{i, i.ToString()});}
This runs in 03.2422335 seconds, a significant improvement, but we can do even more, I think.
We start by making the required definitions:
static ConstructorInfo ctor = typeof(Created).GetConstructors()[0];delegate Created CreateCtor(int i, string s);static CreateCtor createdCtorDelegate;
Then we generate a dynamic method to create the object, and turn that into a delegate:
DynamicMethod method = new DynamicMethod("CreateIntance", typeof(Created),new Type[] { typeof(int), typeof(string) });ILGenerator gen = method.GetILGenerator();gen.Emit(OpCodes.Ldarg_0);// igen.Emit(OpCodes.Ldarg_1);// sgen.Emit(OpCodes.Newobj, ctor);// new Createdgen.Emit(OpCodes.Ret);createdCtorDelegate = (CreateCtor)method.CreateDelegate(typeof(CreateCtor));
Now, in the method itself, all we have to do is call this delegate:
private static Created CreateInstance(int i){return createdCtorDelegate(i, i.ToString());}
And now that run very fast... 00.4314517 seconds. Almost as fast as our baseline. But this is not really a good example, I am afraid. At least, not a god example of generally creating instances, let us make this into the more general form, shall we?
We will change the CreateCtor delegate to the following signature:
delegate object CreateCtor(object[] args);
And the generation of the dynamic method to use the generic approach:
DynamicMethod method = new DynamicMethod("CreateIntance", typeof(Created),new Type[] { typeof(object[]) });ILGenerator gen = method.GetILGenerator();gen.Emit(OpCodes.Ldarg_0);//arrgen.Emit(OpCodes.Ldc_I4_0);gen.Emit(OpCodes.Ldelem_Ref);gen.Emit(OpCodes.Unbox_Any, typeof(int));gen.Emit(OpCodes.Ldarg_0);//arrgen.Emit(OpCodes.Ldc_I4_1);gen.Emit(OpCodes.Ldelem_Ref);gen.Emit(OpCodes.Castclass, typeof(string));gen.Emit(OpCodes.Newobj, ctor);// new Createdgen.Emit(OpCodes.Ret);createdCtorDelegate = (CreateCtor)method.CreateDelegate(typeof(CreateCtor));
We need to make the following modification to our CreateInstance method:
private static Created CreateInstance(int i){return (Created)createdCtorDelegate(new object[]{i, i.ToString()});}
And now it runs in.... 00.5018288.
Now, what does this long and arcane post tells us?
Creating instances, no matter how many, is really cheap. Remember that I had to do a million iteration to get something measurable.
The table bellow give the final statistics. Pay attention to the last column, this gives the amount of time it take to create a single instance. Even the most hard core perf fanatic would be hard pressed to argue over 0.000007 seconds. At least I hope so :-)
| Create single instance | Iterations | Time | Method |
| 0.00000036481170000000 | 1000000 |
0.36481
|
new |
| 0.00000682426360000000 | 1000000 |
6.82426
|
Activator |
| 0.00000324223350000000 | 1000000 |
3.24223
|
GetUninitializedObject |
| 0.00000050182880000000 | 1000000 |
0.50183
|
Dynamic Method |
And just to clarify, you are not going to see anything like creating a million object in most scenarios that you care about. In other words, you can probably leave things well enough alone.

Comments
Comment preview