具有原始类型的Java代码的效率

pio*_*k89 2 java performance jvm primitive-types

我想问一下Java中哪一段代码效率更高?代码1:

void f()
{
 for(int i = 0 ; i < 99999;i++)
 {
  for(int j = 0 ; j < 99999;j++)
  {
   //Some operations
  }
 }

}
Run Code Online (Sandbox Code Playgroud)

代码2:

void f()
{
 int i,j;
 for(i = 0 ; i < 99999;i++)
 {
  for(j = 0 ; j < 99999;j++)
  {
   //Some operations
  }
 }

}
Run Code Online (Sandbox Code Playgroud)

我的老师说第二个更好,但我不同意这个意见.

pol*_*nts 31

它.不.使.A.差异.

停止微优化.这些小技巧不会使程序运行得更快.

专注于大图优化和编写可读代码.

声明它们有意义的变量,以及它有助于在更大的上下文中理解整个代码的语义,而不是因为你认为它比另一个更快.


Ano*_*ose 17

我更喜欢第一个,因为它使循环变量不受方法中其余代码的影响.由于它们在循环外部不可见,因此您不能在以后偶然引用它们.

其他答案也是正确的:不要担心这种性能问题.但不要去想它了代码的可读性的原因,并为程序员的意图传达给谁出现的下一个人.这比微优化问题重要得多.

现在,这是Java语言(如Java语言规范)级别.在Java虚拟机级别,它使用这两者中的哪一个完全没有区别.本地人以完全相同的方式分配.

如果您不确定,可以随时编译它,看看会发生什么.让我们为两个版本制作两个类f1和f2:

$ cat f1.java
public class f1 {
  void f() {
    for(int i = 0 ; i < 99999;i++) {
      for(int j = 0 ; j < 99999;j++) {
      }
    }
  }
}

$ cat f2.java
public class f2 {
  void f() {
    int i, j;
    for(i = 0 ; i < 99999;i++) {
      for(j = 0 ; j < 99999;j++) {
      }
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

编译它们:

$ javac f1.java
$ javac f2.java
Run Code Online (Sandbox Code Playgroud)

并反编译它们:

$ javap -c f1 > f1decomp
$ javap -c f2 > f2decomp
Run Code Online (Sandbox Code Playgroud)

并比较它们:

$ diff f1decomp f2decomp
1,3c1,3
< Compiled from "f1.java"
< public class f1 extends java.lang.Object{
< public f1();
---
> Compiled from "f2.java"
> public class f2 extends java.lang.Object{
> public f2();
Run Code Online (Sandbox Code Playgroud)

字节码完全没有区别.


Ste*_*n C 13

谨防微基准测试的危险!

我拿了代码,在外面包裹了一个方法,并在循环中运行了10次.结果:

50, 3, 
3, 0, 
0, 0, 
0, 0, 
....
Run Code Online (Sandbox Code Playgroud)

如果循环中没有一些实际代码,编译器就能够确定循环没有任何有用的工作并完全优化它们.鉴于测量的性能,我怀疑这种优化可能已经完成了javac.

第1课:编译器通常会优化掉无用"工作"的代码.编译器越聪明,就越有可能发生这种事情.如果您不以编码的方式允许这样做,那么基准测试可能毫无意义.

所以我在两个循环中添加了以下简单计算if (i < 2 * j) longK++;,并使测试方法返回最终值longK.结果:

32267, 33382,
34542, 30136,
12893, 12900,
12897, 12889,
12904, 12891,
12880, 12891,
....
Run Code Online (Sandbox Code Playgroud)

我们显然已经停止了编译器优化循环.但现在我们看到JVM预热(在这种情况下)前两对循环迭代的影响.前两对迭代(一个方法调用)可能纯粹在解释模式下运行.它看起来第三次迭代实际上可能与JIT并行运行.通过第三对迭代,我们很可能运行纯本机代码.从那时起,两个版本的循环时序之间的差异就是噪音.

第2课:始终考虑JVM预热的影响.这可能会严重扭曲微观和宏观的基准测试结果.

结论 - 一旦JVM预热,两个版本的循环之间就没有可测量的差异.

  • +1是一个很好的解释,JVM/JIT的过程优化效果的例子.我自己的想法,人们似乎经常忘记编译的代码不必是逐字编写的代码,如果它在计算上是等价的,即通过智能编译器将递归的fibonnaci转换为简单循环的经典示例(在它到达之前) JVM/JIT). (3认同)

cle*_*tus 6

第二个更糟糕.

为什么?因为循环变量的作用域是循环外部的.i并且j循环完成后,将有一个值.一般来说,这不是你想要的.第一个范围是循环变量,因此它只在循环中可见.