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

maa*_*nus 5 java compiler-optimization guava

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

static int slowItDown() {
    int result = 0;
    for (int i = 1; i <= 1000; i++) {
        result += i;
    }
    return result;
}
Run Code Online (Sandbox Code Playgroud)

这是恕我直言,这是一个非常糟糕的主意,因为它的身体可以被取代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;
}
Run Code Online (Sandbox Code Playgroud)

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

1与我最初写的相反; 我必须看到一些不存在的东西.

Hol*_*ger 3

嗯,JVM确实优化掉了这样的代码。问题是,在以这种方式进行分析之前,必须将其检测为真正的热点多少次(基准测试通常比这种单一方法执行更多操作)。在我的设置中,执行时间(几乎)为零之前需要 16830 次调用。

\n\n

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

\n\n

更新:我简化了代码,优化来得更早。

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

\xe2\x80\xa6

\n\n
execution time: 0 ns\nafter 15300 invocations\n1.7.0_13\n23.7-b01\n
Run Code Online (Sandbox Code Playgroud)\n\n

(64位服务器虚拟机)

\n