46

Is the following:

MyObject myVariable;
for(int i = 0; i < objects.Length, i++){
  myVariable = objects[i];
  // do stuff...
}

more efficient then:

for(int i = 0; i < objects.Length, i++){
  MyObject myVariable = objects[i];
  // do stuff...
}

because a new variable to hold a reference is not created every time? (or is the complier intelligent enough just to use the same variable)..

(If a new variable is created is it malloced on the heap?)

svick
  • 236,525
  • 50
  • 385
  • 514
markmnl
  • 11,116
  • 8
  • 73
  • 109
  • 1
    short answer: no, becuase myVariable's scope is the method it is in and a new variable to hold the reference is not created despite being declared within a for loop. – markmnl May 14 '12 at 02:41

3 Answers3

83

No, "variables" exist almost entirely for the sake of the programmer. You're not creating any additional work at run-time by declaring the variable inside the method.

In theory, the compiler will set aside space on the stack when a method is called for each variable declared in that method. So the presence of that variable in the method would be more important than its scope. No space is allocated on the heap unless the new keyword is used.

In practice, the compiler can identify variables that have such a short scope that they can be stored in a register on the CPU instead of needing space on the stack. For example:

var a = b[c];
a.ToString();
// never access "a" again.

... would be the same as:

b[c].ToString();

... because the compiler recognizes that it only needs to store the result of b[c] long enough to call a method on it, so it can just use a CPU register instead of using memory.

For this reason, declaring your variable inside the loop could actually cause the method to allocate less stack space for the variable, depending on the possible logic flow afterward. However, that gets into huge micro-optimization that doesn't make any sense for most people to care about.

Update

Since some people still seem to think that declaring a variable in a loop has some effect, I guess I need to provide proof. Type the following programs into LINQPad.

int j;
for(int i = 0; i < 5; i++)
{
    j = i;
}

... and...

for(int i = 0; i < 5; i++)
{
    int j = i;
}

Execute the code, then go to the IL tab to see the generated IL code. It's the same for both of these programs:

IL_0000:  ldc.i4.0    
IL_0001:  stloc.0     
IL_0002:  br.s        IL_0008
IL_0004:  ldloc.0     
IL_0005:  ldc.i4.1    
IL_0006:  add         
IL_0007:  stloc.0     
IL_0008:  ldloc.0     
IL_0009:  ldc.i4.5    
IL_000A:  blt.s       IL_0004

So there's incontrovertible proof that this will make no difference at compile time. You'll get exactly the same compiled IL from both programs.

Community
  • 1
  • 1
StriplingWarrior
  • 151,543
  • 27
  • 246
  • 315
  • 7
    Declaring inside the loop can also help the optimizer, since it now knows that (1) the variable is not used outside the loop, and (2) the value from the previous iteration does not need to be carried forward to the next iteration. – Raymond Chen Sep 12 '11 at 03:52
  • 3
    @Raymond: The optimizer can typically know all of that no matter where the local variable is declared. – Eric Lippert Sep 12 '11 at 05:20
  • 1
    True. This was more of a "lazy compiler" optimization. (Which often corresponds to "lazy other developer reading your code".) – Raymond Chen Sep 12 '11 at 12:31
  • 2
    Declaring inside the loop could also help the *lazy other developer reading your code* since *he/she* now knows that ... ;-) – StriplingWarrior Sep 12 '11 at 14:03
  • Would this change if the variable being declared was an object like a ListItem being added to a DropDownList, where the new keyword is used each iteration? – Jason Kelley Jan 22 '14 at 17:27
  • @Loophole: No. Invoking the constructor is going to take time, so if you can reuse the actual *object* (in your case, a `ListItem`), then that would improve performance somewhat. But reusing the declared variable will have no effect. – StriplingWarrior Feb 04 '14 at 20:43
  • What about double j = (Math.PI/180); It would be the same inside or outside the loop? – Pedro77 Jan 14 '15 at 15:41
  • 1
    @Pedro77: The compiler can tell that `Math.Pi/180` is a constant, so it will replace `Math.Pi/180` with its precalculated value. If you put the *declaration* (`double j`) in different places, you'll see no difference in IL code. If you put the *assignment* (`j = ...`) in different places, the IL code will be different. However, the JIT compiler will most likely notice if `j` is never changed or never used, and optimize it away. – StriplingWarrior Jan 14 '15 at 19:05
  • @StriplingWarrior, I always put the code outside the loop for "optimization". Now I know I don't need to do that. Thanks for the info! – Pedro77 Jan 15 '15 at 11:01
  • 1
    @Pedro77: Let me be clear: if you calculate based on a value only known at runtime, like some `list.Length` or something, there would be a small performance improvement by putting that value into a variable first and using the variable in the loop. The difference would probably be barely measurable, and not really noticeable, but it would be there. Even then, it's the *calculation* and *assignment* that cause work, not the *declaration*. But when working with constants, the compiler can simply precalculate the results, and it knows there will be no change in side-effects. – StriplingWarrior Jan 15 '15 at 16:38
1

I did Benchmark the "Problem" and agree with StriplingWarrior. At least it makes no difference in terms of speed.

long start = Time();
long end = Time();
Console.WriteLine("Benchmark Runtime: " + (end - start) + " Microseconds");

for(int k = 0; k < 5; k++)
{
    start = Time();
    int j;
    for (int i = 0; i < 900000000; i++)
    {
        j = i;
    }
    end = Time();
    Console.WriteLine("Benchmark 1: " + (end - start) + " Microseconds");
}

for (int k = 0; k < 5; k++)
{
    start = Time();
    for (int i = 0; i < 900000000; i++)
    {
        int j = i;
    }
    end = Time();
    Console.WriteLine("Benchmark 2: " + (end - start) + " Microseconds");
}

Results:

Benchmark Runtime: 1 Microseconds
Benchmark 1: 1730816 Microseconds
Benchmark 1: 1725885 Microseconds
Benchmark 1: 1725629 Microseconds
Benchmark 1: 1726052 Microseconds
Benchmark 1: 1726121 Microseconds
Benchmark 2: 1725843 Microseconds
Benchmark 2: 1725576 Microseconds
Benchmark 2: 1726233 Microseconds
Benchmark 2: 1725786 Microseconds
Benchmark 2: 1729965 Microseconds
Dennz
  • 11
  • 2
-5

short answer, yes.

long answer, yes it is faster, but hardly noticeable unless repeated many times. :-)

I am not sure if the compiler will optimize it or not, I doubt it though, and if it does, good for it, you should still write it as if it doesn't, make it a habbit.

Krum110487
  • 611
  • 1
  • 7
  • 20
  • 7
    I disagree with this answer. It's not faster, and it's not preferable from a coding practices standpoint. You want to keep variables scoped as narrowly as possible to avoid confusion and conflicts for other programmers. – StriplingWarrior Sep 12 '11 at 03:52
  • I was under the impression that declaring a variable within the loop will run the initialization each time the loop is ran, thus slowing the process down (even though it isn't much). and having it outside is the same but take out the initialization part and simply assign the values. Thus a bit faster. – Krum110487 Sep 12 '11 at 04:23
  • 6
    A lot of people are under that impression until they take a compilers course. Once you understand how a compiler looks at things, it totally makes sense that a compiler will only allocate stack space for the variable once per method. In fact, it will often recycle the space it allocates for a variable, using it for multiple variables in the method if it can determine that those variables could never possibly be needed at the same time. – StriplingWarrior Sep 12 '11 at 14:07
  • when I say initialize, I don't exactly mean create a new variable, I mean the initialize code is ran. I have taken a compilers course. The initialize code will be ran even though it isn't creating a new variable. so technically it is slower, just not because it is being allocated memory space. but nothing to go out of your way for. Now that I re-read the question, I guess I should have validated my answer, which would basically be "no" now :-) – Krum110487 Sep 12 '11 at 23:48
  • 5
    If you were creating a new object, it would initialize the object. If you were setting the variable to have a value (null, constant, or otherwise), it might initialize the piece of memory that is allocated for that variable (assuming the compiler couldn't optimize it away). But simply *declaring* a variable inside a loop does not add any actual code to be run at compile time. I'll update my answer with more details. – StriplingWarrior Sep 13 '11 at 15:21