One*_*ree 3 java compiler-construction compiler-optimization
假设我有这门课
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*/ }
}
Run Code Online (Sandbox Code Playgroud)
FLAG显然永远不会改变。假设Util.doSomething()被大量使用(并且在许多关键的地方,性能确实很重要)。Java 编译器或 JVM 是否足够聪明,可以缓存主体,doSomething以便代码不必重新计算FLAG或重新执行分支指令?
我该如何检查这个?
谢谢
这可能取决于您使用的 JVM。对于 Oracle Hotspot JVM,您可以使用以下命令检查生成的机器代码
java -server -XX:+UnlockDiagnosticVMOptions -XX:+PrintAssembly your.MainClass
Run Code Online (Sandbox Code Playgroud)
前提是您在库路径中有必要的本机库(文档提到您可以在哪里获取此类二进制文件)。
运行班级:
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);
}
}
Run Code Online (Sandbox Code Playgroud)
和
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)
Run Code Online (Sandbox Code Playgroud)
在我的 Intel 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
Run Code Online (Sandbox Code Playgroud)
也就是说, 的测试FLAG和调用都已bar()作为死代码被消除,并且foo内联的方法体。
| 归档时间: |
|
| 查看次数: |
147 次 |
| 最近记录: |