我一直想知道,在一般情况下,在循环之前声明一个丢弃的变量,而不是在循环内部重复,使任何(性能)差异? Java中的一个(非常无意义的)例子:

A)循环前声明:

double intermediateResult;
for(int i=0; i < 1000; i++){
    intermediateResult = i;
    System.out.println(intermediateResult);
}

B)声明(重复)内部循环:

for(int i=0; i < 1000; i++){
    double intermediateResult = i;
    System.out.println(intermediateResult);
}

哪个更好,a还是b?

我怀疑重复的变量声明(例b)在理论上会产生更多的开销,但编译器足够聪明,所以这无关紧要。例b的优点是更紧凑,并且将变量的作用域限制在使用它的地方。尽管如此,我还是倾向于根据示例a编写代码。

编辑:我对Java案例特别感兴趣。


当前回答

A)比B).........更安全想象一下,如果你在循环中初始化结构而不是'int'或'float'然后呢?

就像

typedef struct loop_example{

JXTZ hi; // where JXTZ could be another type...say closed source lib 
         // you include in Makefile

}loop_example_struct;

//then....

int j = 0; // declare here or face c99 error if in loop - depends on compiler setting

for ( ;j++; )
{
   loop_example loop_object; // guess the result in memory heap?
}

您肯定会遇到内存泄漏的问题!因此,我认为“A”是更安全的赌注,而“B”是容易受到内存积累的影响,特别是工作在近源库中。你可以在Linux上使用“Valgrind”工具检查,特别是子工具“Helgrind”。

其他回答

我的做法如下:

如果变量类型为simple (int, double,…)我更喜欢变种b(里面的)。 原因:减少变量的范围。 如果变量的类型不简单(某种类或结构),我更喜欢变量a(外部)。 原因:减少与医生的通话次数。

我认为这取决于编译器,很难给出一个一般的答案。

这是更好的形式

double intermediateResult;
int i = byte.MinValue;

for(; i < 1000; i++)
{
intermediateResult = i;
System.out.println(intermediateResult);
}

1)这样声明一次时间既是变量,而不是每次为周期。 2)任务比其他选项都要大。 3)所以最佳实践规则是迭代之外的任何声明。

很长一段时间我都有同样的问题。所以我测试了一段更简单的代码。

结论:对于此类病例,两组间无显著性差异。

外环箱

int intermediateResult;
for(int i=0; i < 1000; i++){
    intermediateResult = i+2;
    System.out.println(intermediateResult);
}

内环箱

for(int i=0; i < 1000; i++){
    int intermediateResult = i+2;
    System.out.println(intermediateResult);
}

我检查了IntelliJ的反编译器上的编译文件,对于这两种情况,我得到了相同的Test.class

for(int i = 0; i < 1000; ++i) {
    int intermediateResult = i + 2;
    System.out.println(intermediateResult);
}

我还使用这个答案中给出的方法对这两种情况的代码进行了反汇编。我将只展示与答案相关的部分

外环箱

Code:
  stack=2, locals=3, args_size=1
     0: iconst_0
     1: istore_2
     2: iload_2
     3: sipush        1000
     6: if_icmpge     26
     9: iload_2
    10: iconst_2
    11: iadd
    12: istore_1
    13: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
    16: iload_1
    17: invokevirtual #3                  // Method java/io/PrintStream.println:(I)V
    20: iinc          2, 1
    23: goto          2
    26: return
LocalVariableTable:
        Start  Length  Slot  Name   Signature
           13      13     1 intermediateResult   I
            2      24     2     i   I
            0      27     0  args   [Ljava/lang/String;

内环箱

Code:
      stack=2, locals=3, args_size=1
         0: iconst_0
         1: istore_1
         2: iload_1
         3: sipush        1000
         6: if_icmpge     26
         9: iload_1
        10: iconst_2
        11: iadd
        12: istore_2
        13: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
        16: iload_2
        17: invokevirtual #3                  // Method java/io/PrintStream.println:(I)V
        20: iinc          1, 1
        23: goto          2
        26: return
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
           13       7     2 intermediateResult   I
            2      24     1     i   I
            0      27     0  args   [Ljava/lang/String;

如果您仔细注意,在LocalVariableTable中,只有分配给i和intermediateResult的Slot会根据它们的出现顺序进行交换。slot中的相同差异也反映在其他代码行中。

当前无额外操作 在这两种情况下,intermediateResult仍然是一个局部变量,因此访问时间没有差异。

奖金

编译器做了大量的优化,看看在这种情况下发生了什么。

零工作情况

for(int i=0; i < 1000; i++){
    int intermediateResult = i;
    System.out.println(intermediateResult);
}

零工作反编译

for(int i = 0; i < 1000; ++i) {
    System.out.println(i);
}

我用Node 4.0.0测试了JS,如果有人感兴趣的话。在循环外声明会导致~。平均超过1000次试验,每次试验1亿次循环,性能提高5毫秒。所以我要用最易读/可维护的方式来写,在我看来就是B。我本想把我的代码放在小提琴中,但我使用了现在性能的Node模块。代码如下:

var now = require("../node_modules/performance-now")

// declare vars inside loop
function varInside(){
    for(var i = 0; i < 100000000; i++){
        var temp = i;
        var temp2 = i + 1;
        var temp3 = i + 2;
    }
}

// declare vars outside loop
function varOutside(){
    var temp;
    var temp2;
    var temp3;
    for(var i = 0; i < 100000000; i++){
        temp = i
        temp2 = i + 1
        temp3 = i + 2
    }
}

// for computing average execution times
var insideAvg = 0;
var outsideAvg = 0;

// run varInside a million times and average execution times
for(var i = 0; i < 1000; i++){
    var start = now()
    varInside()
    var end = now()
    insideAvg = (insideAvg + (end-start)) / 2
}

// run varOutside a million times and average execution times
for(var i = 0; i < 1000; i++){
    var start = now()
    varOutside()
    var end = now()
    outsideAvg = (outsideAvg + (end-start)) / 2
}

console.log('declared inside loop', insideAvg)
console.log('declared outside loop', outsideAvg)