1

最近,我遇到了一个静态代码分析工具 (PMD) 抱怨switch语句分支太少的情况。它建议把它变成一个 if 语句,我不想​​这样做,因为我知道很快就会添加更多的案例。但我想知道是否javac执行了这样的优化。我使用 JAD 反编译了代码,但它仍然显示一个开关。这可能是 JIT 优化的运行时吗?

更新:请不要被我的问题的上下文误导。我不是在问 PMD,我不是在问是否需要微优化等。问题显然只是这样:当前(Oracle 1.6.x)JVM 实现是否包含一个处理开关的 JIT是否有几个分支。

4

4 回答 4

2

确定 JIT 编译器如何优化 switch 语句的方法是:

  • 阅读 JIT 编译器源代码(OpenJDK 6 和 7 是开源的),或者
  • 使用开关运行 JVM,该开关告诉它将感兴趣的类的 JIT 编译代码转储到文件中。

请注意,与所有与性能和优化相关的问题一样,答案取决于硬件平台以及 JVM 供应商和版本。

参考:反汇编 Java JIT 编译的原生字节码


如果这个问题是“纯粹的好奇心”,那就这样吧。

但是,还应该指出,重写代码以使用switchif出于性能原因可能是一个坏主意和/或浪费时间。

  • 这可能是浪费时间,因为原始版本和手动优化版本之间的时间差异(如果有的话)可能微不足道。

  • 这是一个坏主意,因为您的优化可能只对特定的硬件和 JVM 组合有帮助。在其他人身上,它可能没有效果......甚至是反优化。

简而言之,即使您知道 JIT 优化器如何处理这个问题,您也可能不应该在您的编程中考虑到它。

(当然,例外情况是当您遇到真正可衡量的性能问题时,并且分析指出(例如)3 分支switch是瓶颈之一。)

于 2012-09-12T11:54:57.370 回答
1

如果你是在debug模式下编译的,反编译的时候还是能拿到switch是很正常的。否则,任何调试尝试都会遗漏一些信息,例如行号和原始指令流。
因此,您可以尝试在生产模式下编译并查看反编译结果。

然而,switch 语句,特别是如果它预计会增长,通常被认为是代码异味,应该被评估为重构的良好候选者。

于 2012-09-12T11:34:41.677 回答
1

至于在你澄清问题是什么之后。

由于这对硬件和 JVM 有很大的影响(使用 Java 商标的 JVM 可能由 Oracle 以外的公司开发,只要它们遵守 JVM 规范)我说唯一有效的方法是进行速度测试。

剪下一段代码,将其锁定在一个循环中进行大量重复,检查循环执行前后的时间。对两种解决方案重复(switch 和 if)

这可能看起来简单而愚蠢,但它确实有效,并且比反编译、读取字节码和内存转储等要快得多。


您必须记住,Java 实际上使用虚拟机和字节码。我很确定这一切都得到了处理和优化。我们正在使用高级语言来避免您询问的此类微观管理和优化

在更一般的说明中,我认为您尝试优化有点为时过早。如果你知道在那个开关中会有更多的案例,为什么还要麻烦呢?您是否运行了分析器?如果没有,它没有用优化。“过早的优化是万恶之源”。您可能正在优化实际上不是瓶颈的代码部分,增加代码复杂性并浪费您自己的时间编写无任何贡献的代码。

我不知道你正在制作什么类型的应用程序,但经验法则说清晰是王道,你通常应该选择更简单、更优雅、自我记录的解决方案。

于 2012-09-12T11:41:33.607 回答
0

javac 性能几乎没有优化。所有优化都是在运行时使用 JIT 执行的。除非您知道自己有性能问题,否则我会假设您没有。

PMD 抱怨的是清晰度。例如

if (a == 5) {
  // something
} else {
  // something else
}

switch(a) {
   case 5:
       // something
       break;
   default:
       // something else
       break;
}
于 2012-09-12T11:31:23.320 回答