即时编译——它实际上是什么时候在Java中发生的?

即时编译——它实际上是什么时候在Java中发生的?,java,performance,jit,Java,Performance,Jit,最近我参加了一次关于Java效率的讨论。 正如我所听到的,很多反对Java的论点都认为解释“非常耗时”,因此即使是简单的Java程序也比直接编译成机器代码的类似程序运行得慢 对此的答案是,Java代码通常直接编译成机器代码,只要JVM进行计算,它就会使程序比以标准方式进行解释更快 我的问题是:JVM何时真正“决定”执行实时编译?使JIT比标准字节码解释更高效的标准是什么?我的意思是,编译本身需要一些时间,据我所知,这一切都应该在程序已经运行时发生?这取决于您的JVM及其设置。维基百科: 例如,S

最近我参加了一次关于Java效率的讨论。 正如我所听到的,很多反对Java的论点都认为解释“非常耗时”,因此即使是简单的Java程序也比直接编译成机器代码的类似程序运行得慢

对此的答案是,Java代码通常直接编译成机器代码,只要JVM进行计算,它就会使程序比以标准方式进行解释更快


我的问题是:JVM何时真正“决定”执行实时编译?使JIT比标准字节码解释更高效的标准是什么?我的意思是,编译本身需要一些时间,据我所知,这一切都应该在程序已经运行时发生?

这取决于您的JVM及其设置。维基百科:

例如,Sun的Java虚拟机有两种主要模式:客户端和服务器。在客户机模式下,执行最小的编译和优化,以减少启动时间。在服务器模式下,执行广泛的编译和优化,以牺牲启动时间,在应用程序运行后实现性能最大化。其他Java即时编译器使用运行时方法执行次数的测量值,并结合方法的字节码大小,作为决定何时编译的启发式方法。[4]还有一个使用执行次数并结合循环检测。[5]

对于服务器模式中的vanilla HotSpot JVM,一个粗略的近似值是,当JVM注意到某个方法被多次调用(通常超过某个特定次数)时,就会发生JIT。(这就是为什么JVM被称为“热点”——因为它识别并优化代码中的“热点”)

  • 它知道这个方法值得花时间去优化,因为它经常被调用
  • 它非常了解此函数的实际特性:
    • 如果
      if
      语句的一个分支比另一个分支更常见,那么它可以改进
    • 例如,如果传递给此方法的
      列表
      通常是
      数组列表
      ,则它可以针对
      数组列表
      的特定情况进行优化和内联
请注意,如果您提前编译机器代码,您就不会有太多的这些信息需要优化——编译器事先不知道哪些路径比其他路径更常见。但是,如果您等到获得真实数据后再进行优化,则可以做出更好的优化决策


关于JIT所做的更多细节如下。

参考:+1表示“某个方法被多次调用”。。。“它知道这个方法经常被调用”:)但说真的,这是个好答案。我不确定我是否理解得很好,但JVM只知道一个方法在被多次调用之后才经常被调用。我的意思是,当JVM“在线”解释字节码时,它不“知道”一个方法会被再次调用多少次,对吗?或者编译器在编译时将这些信息添加到字节码中?如果不是,那么这个方法总是有可能只是在程序开始时被多次调用,后来就没有使用过——在这种情况下,如果JVM用这种方法执行JIT,它只会浪费时间(或者如果这个方法本身很大的话,会浪费很多时间);它猜测,如果一个方法以前被称为lots,它将继续被称为lots。但在实践中,这是一个完全有效的假设。因此,我所描述的风险被简单地考虑进去,因为在实践中,它不会经常发生。考虑到这一事实,Java不应该比直接编译成机器代码的代码慢很多。我的意思是,启动(服务器)可能需要更多的时间,但当它已经运行时,应该会非常快。我的逻辑正确吗?(在同一次讨论中,我听说Java虚拟机本身相当不错)。这……有点准确。在某些方面,Java可能比预编译的机器代码快,因为它更了解代码的运行时特征,但Java在启动和“预热”代码热点方面可能比其他语言慢。