为什么这种方法没有得到优化?

时间:2013-09-06 22:20:40

标签: java guava compiler-optimization

Java method用于基准测试以模拟慢速计算:

static int slowItDown() {
    int result = 0;
    for (int i = 1; i <= 1000; i++) {
        result += i;
    }
    return result;
}

这是恕我直言,这是一个非常糟糕的主意,因为它的身体可以被return 500500取代。 这似乎永远不会发生 1 ;可能是因为这样的优化与Jon Skeet所说的实际代码无关。

有趣的是,一个稍微简单的result += 1;方法得到了完全优化(卡尺报告为0.460543 ns)。

但即使我们同意优化远离返回常量结果的方法对于实际代码也没用,但仍然存在循环展开,这可能会导致类似

static int slowItDown() {
    int result = 0;
    for (int i = 1; i <= 1000; i += 2) {
        result += 2 * i + 1;
    }
    return result;
}

所以我的问题仍然存在:为什么这里没有进行优化?

1 与我最初写的相反;我一定见过那些不存在的东西。

1 个答案:

答案 0 :(得分:3)

好吧,JVM 优化了这些代码。问题是在用这种方式进行分析之前,它必须被检测为多少次真正的热点(基准测试通常比这种方法更多)。在我的设置中,它需要16830次调用才能执行时间(几乎)为零。

这样的代码没有出现在实际代码中是正确的。但是,它可能在其他热点的几个内联操作之后仍然存在,这些热点处理的值不是编译时常量,而是运行时常量或事实上的常量(理论上可能会改变但实际上不会改变的值)。当这样的代码仍然存在时,完全优化它是一个很大的好处,但预计不会很快发生,即从主方法调用时。

更新:我简化了代码,甚至更早地进行了优化。

public static void main(String[] args) {
  final int inner=10;
  final float innerFrac=1f/inner;
  int count=0; 
  for(int j=0; j<Integer.MAX_VALUE; j++) {
    long t0=System.nanoTime();
    for(int i=0; i<inner; i++) slowItDown();
    long t1=System.nanoTime();
    count+=inner;
    final float dt = (t1-t0)*innerFrac;
    System.out.printf("execution time: %.0f ns%n", dt);
    if(dt<10) break;
  }
  System.out.println("after "+count+" invocations");
  System.out.println(System.getProperty("java.version"));
  System.out.println(System.getProperty("java.vm.version"));
}
static int slowItDown() {
  int result = 0;
  for (int i = 1; i <= 1000; i++) {
      result += i;
  }
  return result;
}

...

execution time: 0 ns
after 15300 invocations
1.7.0_13
23.7-b01

(64位服务器虚拟机)