引用类型变量回收——如果在循环中声明,则在每个循环中创建一个新的引用变量

本文关键字:引用 循环 变量 创建 一个 类型变量 如果 声明 | 更新日期: 2023-09-27 18:08:11

是:

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

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

,因为保存引用的新变量不是每次都创建?(或者编译器是否足够智能,只使用相同的变量).

(如果创建了一个新变量,它是否在堆上嵌套了?)

引用类型变量回收——如果在循环中声明,则在每个循环中创建一个新的引用变量

不,"变数";几乎完全是为了程序员而存在的。通过在方法内部声明变量,您不会在运行时创建任何额外的工作。

理论上,当调用方法中声明的每个变量时,编译器会在堆栈上留出空间。因此,该变量在方法中的存在比它的作用域更重要。除非使用了new关键字,否则不会在堆上分配空间。

在实践中,编译器可以识别具有如此短作用域的变量,它们可以存储在CPU上的寄存器中,而不需要堆栈空间。例如:

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

…与

相同
b[c].ToString();

…因为编译器认识到它只需要存储b[c]的结果足够长的时间来调用它的方法,所以它可以使用CPU寄存器而不是使用内存。

由于这个原因,在循环中声明变量实际上可能会导致方法为变量分配更少的堆栈空间,这取决于之后可能的逻辑流。然而,这涉及到一个巨大的微优化,对大多数人来说没有任何意义。

更新

由于有些人似乎仍然认为在循环中声明变量有一些效果,我想我需要提供证据。在LINQPad中输入以下程序:

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

…和…

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

执行代码,然后转到IL选项卡查看生成的IL代码。对于这两个程序都是一样的:

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

因此,有无可争议的证据表明,这在编译时不会产生任何影响。您将从两个程序中得到完全相同的编译后的IL。

我对"问题"进行了基准测试,并同意StriplingWarrior的观点。至少在速度上没有区别。

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");
}

结果:

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

简短的回答,是的。

长答案,是的,它是更快,但几乎不明显,除非重复多次。: -)

我不确定编译器是否会优化它,但我怀疑它,如果它做了,很好,你仍然应该写它,如果它没有,使它成为一种习惯。