我已经使用-XX:+PrintCompilation
,我知道JIT编译器的基本技术以及使用JIT编译的原因。
然而,我仍然没有发现JVM如何决定JIT编译一个方法,即#34;当正确的时间来到JIT编译一个方法"。
我是否正确地假设每个方法都开始被解释,并且只要它没有被归类为"热方法"它不会被编译?我脑子里有一些东西,我读到一种方法被认为是热的"当它执行至少10.000次(解释方法10.000次后,它将被编译),但我不得不承认我不确定这个或我在哪里读过这个。
总结一下我的问题:
(1)是否每个方法都被解释,只要它没有被归类为" hot"方法(因此已被编译)或者是否存在方法被编译的原因,即使它们不是" hot"?
(2)JVM如何将方法分类为"非热"和"热"方法?执行次数?还有什么吗?
(3)如果某些阈值(如执行次数)为" hot"方法,是否有Java标志(-XX:...
)来设置此阈值?
答案 0 :(得分:53)
HotSpot编译策略相当复杂,特别是对于分层编译,它在Java 8中默认启用。既不是执行次数,也不是CompileThreshold
参数。
最好的解释(显然,唯一的合理解释)可以在HotSpot来源中找到,请参阅advancedThresholdPolicy.hpp。
我将总结这个高级编译策略的要点:
i
; b
。后向分支通常表示代码中的循环。每次计数器达到特定频率值(TierXInvokeNotifyFreqLog
,TierXBackedgeNotifyFreqLog
)时,都会调用编译策略来决定当前运行的方法下一步该做什么。根据{{1}},i
的值以及C1和C2编译器线程的当前负载,可以决定
此处的关键参数为b
和TierXInvocationThreshold
。根据编译队列的长度,可以针对给定方法动态调整阈值。
编译队列不是FIFO,而是优先级队列。
具有配置文件数据(第3层)的C1编译代码的行为类似,只是切换到下一级别(C2,第4层)的阈值要大得多。例如。在大约200次调用之后,可以在第3层编译解释的方法,而在5000次调用之后,C1编译的方法可以在第4层进行重新编译。
TierXBackEdgeThreshold
,InlineFrequencyRatio
)时,才能内联更大的方法。答案 1 :(得分:9)
控制此问题的主要参数是-XX:CompileThreshold=10000
Java 8的Hotspot现在默认使用分层编译,使用从1级到4级的多个编译阶段。我相信1不是优化。级别3是C1(基于客户端客户端),级别4是C2(基于服务器编译器)
这意味着稍微优化可能比您预期的更早发生,并且在达到10K阈值后可以保持很长时间的优化。我见过的最高点是在一百万次调用后消除StringBuilder的转义分析。
注意:多次循环迭代可以触发编译器。例如10K次的循环就足够了。
1)在方法被认为足够热之前,它被解释。但是,有些JVM(例如Azul Zing)可以在启动时编译方法,您可以强制Hotspot JVM通过内部API编译方法。 Java 9也可能有一个AOT(Ahead Of Time)编译器,但它仍在研究AFAIK
2)呼叫次数或迭代次数。
3)是-XX:CompileThreshold=
是主要的。