假设我有这个课程
Util
{
public static void doSomething()
{
if (FLAG) foo();
else bar();
}
public static void foo() { /* do something */ }
public static void bar() { /* do something else */ }
public static final boolean FLAG = computeFlag();
private static boolean computeFlag() { /* do some computation during init time*/ }
}
FLAG
显然永远不会改变。
假设使用Util.doSomething()
A LOT (并且在许多关键位置,性能确实很重要)。
Java编译器或JVM是否足够智能以缓存doSomething
的主体,以便代码不必重新评估FLAG
或者必须重新执行分支指令?< / p>
我该如何检查?
由于
答案 0 :(得分:4)
这可能取决于您使用的JVM。对于Oracle Hotspot JVM,您可以使用
检查生成的机器代码java -server -XX:+UnlockDiagnosticVMOptions -XX:+PrintAssembly your.MainClass
如果您在库路径中有必要的本机库(documentation提及您可以获取此类二进制文件。)
运行课程:
public class DecompileTest {
public static void doSomething() {
if (FLAG)
foo();
else
bar();
}
static int fooCount;
public static void foo() {
fooCount++;
}
public static void bar() {
fooCount--;
}
public static final boolean FLAG = computeFlag();
private static boolean computeFlag() {
System.out.println("Shall I set the flag? (y/n)");
try {
return System.in.read() == 'y';
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public static void main(String[] args) {
for (int i = 0; i < 1000000; i++) {
doSomething();
}
System.out.println(fooCount);
}
}
带
java version "1.7.0_21"
Java(TM) SE Runtime Environment (build 1.7.0_21-b11)
Java HotSpot(TM) Server VM (build 23.21-b01, mixed mode)
在我的英特尔cpu上产生了一个冗长的disassabmly,相关部分读取:
Decoding compiled method 0x009ca408:
Code:
[Entry Point]
[Verified Entry Point]
[Constants]
# {method} 'doSomething' '()V' in 'stackoverflow/DecompileTest'
# [sp+0x10] (sp of caller)
0x009ca500: sub $0xc,%esp
0x009ca506: mov %ebp,0x8(%esp) ;*synchronization entry
; - stackoverflow.DecompileTest::doSomething@-1 (line 8)
0x009ca50a: mov $0x295dc208,%ebx ; {oop(a 'java/lang/Class' = 'stackoverflow/DecompileTest')}
0x009ca50f: incl 0x70(%ebx) ;*putstatic fooCount
; - stackoverflow.DecompileTest::foo@5 (line 17)
; - stackoverflow.DecompileTest::doSomething@6 (line 9)
0x009ca512: add $0x8,%esp
0x009ca515: pop %ebp
0x009ca516: test %eax,0x950000 ; {poll_return}
0x009ca51c: ret
0x009ca51d: hlt
0x009ca51e: hlt
0x009ca51f: hlt
[Exception Handler]
[Stub Code]
0x009ca520: jmp 0x009c78c0 ; {no_reloc}
[Deopt Handler Code]
0x009ca525: push $0x9ca525 ; {section_word}
0x009ca52a: jmp 0x009ae280 ; {runtime_call}
0x009ca52f: hlt
也就是说,FLAG
的测试和bar()
的调用都已作为死代码被删除,而foo
的方法体已内联。
答案 1 :(得分:1)
是的,这种代码是HotSpot消除死代码的简单目标。即使FLAG
可能发生变化,HotSpot也会通过分析来确定,在实际执行中,它总是相同的,并消除未被删除的分支。