4

Through a question I posted yesterday, it became clear that declaring a variable outside of a loop and instantiating it inside, has no performance benefits over simply moving the declaration to inside the loop, so declaring and instantiating is done at the same time. But what about instantiation? Consider the two options below.

//OPTION 1:
while (_doWork)
{
    Person p = new Person(name = "John", age = 35);
    //work that involves reading (not writing to) p
}

//OPTION 2:
Person p = new Person(name = "John", age = 35);
while (_doWork)
{
    //work that involves reading (not writing to) p
}

For the purposes of this question, the key assumptions are:

  1. p is not needed outside of the loop
  2. p does not get written too (so outcome wise, the two are the same)
  3. There is no outcome reason for why we should keep re-instantiating p (p looks the same in both options)

Question: Which is better performance wise, and which option is better practice?

The answer to this post (despite being about declaration, not instantiation) seems to indicate the latter: Declaring variables inside or outside of a loop

My Thoughts:

  • It just seems like a major waste to me to keep reinstantiating it. Might be okay for primitive types, but for complex classes?
  • int a = 0 is the same as int a = new int(), so I guess the answer to the above also applies to primitive types?
Community
  • 1
  • 1
Magnus
  • 6,791
  • 8
  • 53
  • 84
  • Well it depends entirely what you want to do. – leppie Aug 22 '14 at 08:58
  • possible duplicate of [Declaring a variable inside or outside an foreach loop: which is faster/better?](http://stackoverflow.com/questions/1884906/declaring-a-variable-inside-or-outside-an-foreach-loop-which-is-faster-better) – Paul Zahra Aug 22 '14 at 08:59
  • In addition to be a duplicate, this question appears to be primarily opinion based and is potentially a candidate for code review in 2014 o.O – User 12345678 Aug 22 '14 at 09:00
  • Well, allocation of `int` is really fast (it's anyway just reserving place on stack + initialization). For reference types, it mostly depends on whether your code _expects_ it to be the same instance or different ones. – Vlad Aug 22 '14 at 09:00
  • It isn't reinstatiated on every loop... it is compiled to the same IL so there is no difference speed wise... which leaves the point of readability. – Paul Zahra Aug 22 '14 at 09:01
  • @leppie Assumption is that all i want to do is read the variable inside the loop. ByteBlast: This is not a question about declaration inside vs outside though, but about the entire instantiation. – Magnus Aug 22 '14 at 09:02
  • That is not a duplicate because it's only about declaration and not initialization. – Tim Schmelter Aug 22 '14 at 09:03
  • Does the constructor on Person get fired every time you loop? – Paul Zahra Aug 22 '14 at 09:07
  • Possible duplicate of http://stackoverflow.com/questions/1227290/c-sharp-instantiate-in-foreach-loop – Paul Zahra Aug 22 '14 at 09:10
  • I assume so. @TimeSchmelter would know, but it probably both allocates new memory on heap and stack for reference type (just on stack for value type), and then calls constructor. Over and over again, when not really necessary. I am getting at the fact that this kind of contradicts to concept of creating the variable with the narrowest scope possible. – Magnus Aug 22 '14 at 09:10
  • @PaulZahra: of course the constructor is called on every iteration. How should .NET know whether a method/constructor is redundant or not? Calling constructors can be really expensive or they might even throw exceptions. So in general you should avoid instantiation if you don't have to. OP is confusing declaration with instantiation (and he's not the only one ;)). – Tim Schmelter Aug 22 '14 at 11:00

2 Answers2

3

Which is better performance wise, and which option is better practice?

As per your question, If only a single Person instance is needed, there is no logical reason to instansiate it over and over inside the loop. Allocate it once outside of your loop and use it inside.

About primitive types, you should distinguish between value types (int, long, double) and reference type (string). Value types get allocated on the stack, while reference types get allocated on the heap. Thus, as for your Person class, we will have to allocate the right amount of bytes inside the heap, while allocating an int on the stack is a faster allocation.

Other than best practices, if you want to know which of the two has better performance, benchmark your code. This is the output running in Debug Mode with .NET Framework 4.5, VS2013, on my Intel Core i5 M430:

public class Person
{
    public Person(string name, int age)
    {
        Age = age;
        Name = name;
    }

    public int Age { get; set; }
    public string Name { get; set; }
}

private static void Main(string[] args)
{
   Stopwatch sw = new Stopwatch();
   sw.Start();
   for (int i = 0; i < 1000000; i++)
   {
      Person p = new Person("John", 35);
      var age = p.Age;
      var name = p.Name;
   }

   Console.WriteLine("Loop with inner allocation took {0}", m sw.Elapsed);

   sw.Restart();
   Person px = new Person("John", 35);

   for (int i = 0; i < 1000000; i++)
   {
      var age = px.Age;
      var name = px.Name;
   }

   Console.WriteLine("Loop with outter allocation took {0}", sw.Elapsed)
}

And the results:

Loop with inner allocation took 00:00:00.0708861
Loop with outter allocation took 00:00:00.0155522
Yuval Itzchakov
  • 146,575
  • 32
  • 257
  • 321
  • @PaulZahra Im not sure what you're referring to with that statement? – Yuval Itzchakov Aug 22 '14 at 09:16
  • Great, thank you. Appreciate the code to test speed too, I will use it to compare how the two differs if it is value types that are being used (int) instead. I assume the same principle should apply to value types too though right (even though it is faster)? – Magnus Aug 22 '14 at 09:19
  • Heres the ideone for it... http://ideone.com/kYi0FV this points to it being much much slower, about 35 times! Loop with inner allocation took 00:00:00.0541856 Loop with outter allocation took 00:00:00.0015612 – Paul Zahra Aug 22 '14 at 09:32
  • @YuvalItzchakov While reference types always go on the heap, value types do not always go on the stack, if it is declared in a method it will go on the stack, but if it is declared outside of a method but inside a reference type then it goes on the heap with the reference type. – Paul Zahra Aug 22 '14 at 11:28
  • @PaulZahra - I ment explicitly when allocating a value type inside a method. Ill fix my answer to make that clear. – Yuval Itzchakov Aug 22 '14 at 11:35
1

If you do something 10 times it's less performant than if you do it only once, therefore a single instantiation is more efficient. It's also pointless to intialize an object mutliple times if you only need one instance. That could also have side effects which could make things even worse.

So always declare and initialize it outside of the loop if it doesn't change in the loop. That will also increase readability since everybody can see immediately that this object will most likely not change in the following loop.

Person p = new Person("John", 35);
while (_doWork)
{
    //work that involves reading (not writing to) p
}

If you have to create the object in the loop you should declare it in the loop. But not because it's more performant but more readable.

Read: https://softwareengineering.stackexchange.com/questions/56585/where-do-you-declare-variables-the-top-of-a-method-or-when-you-need-them

Community
  • 1
  • 1
Tim Schmelter
  • 450,073
  • 74
  • 686
  • 939
  • Thank you so much Tim, this is exactly the answer I was looking for. So basically the concept of declaring, instantiating and initializing with the narrowest scope possible (see link in my post), does not apply because it is pointless to keep instantiating it when not needed to.. – Magnus Aug 22 '14 at 09:06
  • @Magnus: exactly. It's pointless to do soemthing 10times if you only have to do it once. Don't confuse delaration and initalization. – Tim Schmelter Aug 22 '14 at 09:12