Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/305.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java jvm是否内联了最终的方法?_Java_Jvm_Hotspot - Fatal编程技术网

Java jvm是否内联了最终的方法?

Java jvm是否内联了最终的方法?,java,jvm,hotspot,Java,Jvm,Hotspot,当我阅读java8规范时,我得到一个声明 在运行时,机器代码生成器或优化器可以“内联”最终方法的主体,用主体中的代码替换方法调用 所以我的问题是热点真的内联了最终的方法吗 或者,是否只有最后一个方法可以内联?比这复杂得多 Hotspot将尽其所能使事情快速运行。唯一的规则是:它不能破坏java规范提供的任何保证 这些保证没有提到“这将是内联的”之类的事情。除非您尝试使用nanoTime(),否则不可能观察到您正在内联,而且java规范显然没有对时间问题做出硬保证-在java规范中,无法观察到的

当我阅读java8规范时,我得到一个声明

在运行时,机器代码生成器或优化器可以“内联”最终方法的主体,用主体中的代码替换方法调用

所以我的问题是热点真的内联了最终的方法吗


或者,是否只有最后一个方法可以内联?

比这复杂得多

Hotspot将尽其所能使事情快速运行。唯一的规则是:它不能破坏java规范提供的任何保证

这些保证没有提到“这将是内联的”之类的事情。除非您尝试使用
nanoTime()
,否则不可能观察到您正在内联,而且java规范显然没有对时间问题做出硬保证-在java规范中,无法观察到的事情很少以某种方式得到保证。为什么要费心保证这些事情呢?这只会妨碍JVM工程师

当前流行的JVM实现使用这种粗略而过于简化的内联计划:

  • 任何方法,final或not,如果看起来是个好主意,都将被内联

  • 这永远不会立即发生。只有选择方法X进行热点重新编译,并且X调用方法Y,并且Y看起来是内联的好方法时,才会发生这种情况

  • 如果内联了一个非final方法,这看起来像是非法移动。然而,事实并非如此:VM只是做出了一个可证伪的假设:“此方法虽然不是最终的,但不会被VM中加载的任何类中的任何内容覆盖”。如果现在为真,则可以内联该方法,即使以后可能不是真的

  • 任何时候加载新类(这归结为:在
    ClassLoader
    的本机
    defineClass
    方法中抛出一个新类),如果这导致任何假设不再为真,就会进行检查。如果发生这种情况,依赖于此假设的所有方法的热插销版本将失效,并将恢复到正常(缓慢,或多或少解释)操作。如果它们仍然大量运行,它们将再次被热插拔,这一次请记住,由于该方法实际上被重写,因此无法再轻松地内联

  • 正如我所说,这就是它现在的工作方式。在未来的java版本中,它的工作方式可能会有所不同,因为这一切都无法保证。它也过于简单化了;例如,我没有提到像
    @jdk.internal.hospotintrinsicandidate
    @java.lang.invokeForceInline
    这样的注释。这是不相关的,通常情况下,您不应该在编写代码时对内联的工作方式持有偏见。关键是你不需要知道


  • 热点内联策略绝非微不足道。影响内联的因素很多

    最重要的是方法的大小和“热度”,以及总内联深度。一个方法是否是最终的并不重要

    HotSpot也可以轻松地内联虚拟方法。它甚至可以内联多态方法,如果频繁接收者不超过2个。有一篇文章详细描述了这种多模态调用是如何工作的

    要分析特定情况下方法的内联方式,请使用以下诊断JVM选项:

    java -XX:+UnlockDiagnosticVMOptions -XX:+PrintCompilation -XX:+PrintInlining
    
    这将输出完整的编译树,其中包含每个方法的原因,以及它是否内联的原因:

    java.util.regex.Pattern$Start::match (90 bytes)
       @ 44   java.util.regex.Pattern$BmpCharProperty::match (55 bytes)   inline (hot)
        \-> TypeProfile (331146/331146 counts) = java/util/regex/Pattern$BmpCharProperty
         @ 14   java.lang.String::charAt (25 bytes)   inline (hot)
          \-> TypeProfile (502732/502732 counts) = java/lang/String
           @ 1   java.lang.String::isLatin1 (19 bytes)   inline (hot)
           @ 12   java.lang.StringLatin1::charAt (28 bytes)   inline (hot)
           @ 21   java.lang.StringUTF16::charAt (11 bytes)   inline (hot)
             @ 2   java.lang.StringUTF16::checkIndex (9 bytes)   inline (hot)
               @ 2   java.lang.StringUTF16::length (5 bytes)   inline (hot)
               @ 5   java.lang.String::checkIndex (46 bytes)   inline (hot)
             @ 7   java.lang.StringUTF16::getChar (60 bytes)   (intrinsic)
         @ 19   java.util.regex.Pattern$CharPredicate::is (0 bytes)   virtual call
         @ 36   java.util.regex.Pattern$Branch::match (66 bytes)   inline (hot)
         @ 36   java.util.regex.Pattern$GroupTail::match (111 bytes)   inline (hot)
          \-> TypeProfile (56997/278159 counts) = java/util/regex/Pattern$GroupTail
          \-> TypeProfile (221162/278159 counts) = java/util/regex/Pattern$Branch
           @ 70   java.util.regex.Pattern$BranchConn::match (11 bytes)   inline (hot)
           @ 70   java.util.regex.Pattern$LastNode::match (45 bytes)   inline (hot)
            \-> TypeProfile (56854/113708 counts) = java/util/regex/Pattern$LastNode
            \-> TypeProfile (56854/113708 counts) = java/util/regex/Pattern$BranchConn
             @ 7   java.util.regex.Pattern$Branch::match (66 bytes)   inline (hot)
              \-> TypeProfile (56598/56598 counts) = java/util/regex/Pattern$Branch
               @ 32   java.util.regex.Pattern$Branch::match (66 bytes)   inline (hot)
               @ 32   java.util.regex.Pattern$GroupHead::match (47 bytes)   already compiled into a big method
                \-> TypeProfile (66852/267408 counts) = java/util/regex/Pattern$GroupHead
                \-> TypeProfile (200556/267408 counts) = java/util/regex/Pattern$Branch
                 @ 32   java.util.regex.Pattern$Branch::match (66 bytes)   recursive inlining is too deep
                 @ 32   java.util.regex.Pattern$GroupHead::match (47 bytes)   already compiled into a big method
                  \-> TypeProfile (66852/267408 counts) = java/util/regex/Pattern$GroupHead
                  \-> TypeProfile (200556/267408 counts) = java/util/regex/Pattern$Branch
                 @ 50   java.util.regex.Pattern$GroupHead::match (47 bytes)   already compiled into a big method
                  \-> TypeProfile (334260/334260 counts) = java/util/regex/Pattern$GroupHead
    
    

    请仔细阅读javadoc。他们故意选了动词“can”。。。。你的问题没有通用的答案。非常感谢你的回答。我是JIT新手,虽然我的问题看起来有点愚蠢,但我只是对它的原理很好奇。附录:即使非最终方法被覆盖,JIT可以在一个特定的调用站点内联该方法,前提是该特定的调用站点仍然总是以原始方法结束,当然,当该假设不再成立时,会进行快速预检查,从而使该方法不再优化。因此,加载子类并不一定会使所有内联代码无效,它可能只会引入插入更多检查的必要性。子类通常只在某些地方使用,而大多数已经运行的代码不会改变其行为。