【问题标题】:Java JIT - scope of dead code elimination?Java JIT - 死代码消除的范围?
【发布时间】:2012-06-13 16:20:24
【问题描述】:

我想知道 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 工作原理的理解完全错误?

【问题讨论】:

  • 如果将 DEBUG 定义为 final,JIT 会更容易
  • 似乎是一个非常具体的问题,可能是 JIT-and-options-and-moon-phase-specific...也许有一种方法可以让特定的 JIT 来解释它的作用?
  • 谢谢,是的——调试应该是最终的,我在输入代码时出错了。如果 JIT 有特定选项可以强制编译 logDebug,我很想知道它们是什么。
  • 真的,这有多大用处?如果代码从未使用过,那么它肯定永远不会被执行吗?你的二进制文件有多大? (更令人担忧的是此类代码的维护,但这不是这里的问题。)
  • 这是为了让我们在编写代码时可以输出一些诊断信息,但在生产时禁用它而不影响性能

标签: java jit


【解决方案1】:

JIT 并不总是完全消除死代码。

相反,它所做的是优化不太可能出现的情况,因此它的成本几乎为零。这是因为 CPU 可以通过分支执行代码的推测执行,如果不采用此分支,则只有名义成本。即使某个分支仅在某些时候被占用,它也会这样做(即它必须选择一个分支作为可能被占用的分支)

如果由于某种原因这种情况发生了变化,代码仍会正常运行,但速度相对较慢。 JIT 可以检测到它所做的优化假设已经改变并重新优化代码。在-XX:+PrintCompilation 你可以看到它转储了之前编译的方法并重新编译。

简而言之,它使死代码几乎没有成本。

【讨论】:

  • 在这种特殊情况下,它应该能够消除死代码。 DEBUG 是一个最终的静态字段,因此 JIT 可以假设它不会改变;无论它是否是运行时常量,也无论理论上是否可以通过反射修改最终的静态字段。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多