我想知道Java JIT编译的使用。我的理解是它应该尝试编译出“死代码”。我想知道的是什么被归类为死代码。
例如- 假设我将名为debug的运行时属性设置为false。 如果我的程序有一些代码来获取该属性,然后基于它执行方法,我想知道什么将被归类为死代码。
public static final boolean DEBUG
static {
DEBUG = System.getProperties().containsKey("debug.enabled");
}
public static void logDebug(String msg) {
if (DEBUG) {
System.out.println("My Debug Message");
}
}
public static void main(String args) {
// 1) Check if DEBUG is true and log if
// it is.
//
if (DEBUG) {
System.out.println("My Debug Message");
}
// 2) Call a method to perform logging, let it check
// DEBUG
//
logDebug("My Second Debug Message");
}
在main中,第一个if块检查DEBUG。因为它是假的,我会假设JIT会意识到这个块永远不会执行,所以将它编译为死代码。
我想知道,如果方法logDebug也会发生同样的情况 - JVM每次都会进入该方法,还是会理解该方法中没有发生任何事情,从而优化它?
也许我对JIT如何运作的理解是完全错误的?
答案 0 :(得分:2)
JIT并不总是完全消除死代码。
相反,它所做的是优化不太可能的情况,因此它几乎没有成本。这是因为CPU可以通过分支执行代码的推测性执行,如果不采用该分支,则只有一个名义上的成本。即使只在某些时候采取分支(即必须选择一个分支作为可能的分支),它也会这样做。
如果由于某种原因这种情况发生了变化,代码仍会正常运行,如果相对较慢的话。 JIT可以检测到它所做的优化假设已经改变并重新优化代码。在-XX:+PrintCompilation
中,您可以看到它转储之前编译的方法并重新编译它。
简而言之,它使得死代码几乎没有成本。