我已经使用-XX:+PrintCompilation,并且我知道JIT编译器的基本技术以及为什么使用JIT编译。
-XX:+PrintCompilation
但是我仍然没有找到JVM如何决定JIT编译方法的方法,即“何时到了JIT编译方法的正确时间”。
我假设每个方法都开始被解释,并且只要它不被归类为“热方法”,就不会被编译,这是对的吗?我脑海里有些东西我读到,当一个方法执行至少10.000次(解释该方法10.000次后,将被编译)时,该方法被视为“热”,但我必须承认不知道这个或我在哪里读过。
所以总结一下我的问题:
(1)是否对每种方法都进行了解释,只要它没有被归类为“热”方法(因此已经被编译),或者即使没有“热”方法也有理由进行编译吗?
(2)JVM如何将方法分为“非热”和“热”方法?执行次数?还要别的吗?
(3)如果“热”方法有某些阈值(如执行次数),是否有Java标志(-XX:...)设置该阈值?
-XX:...
HotSpot编译策略相当复杂,尤其是对于分层编译而言,它在Java 8中是默认启用的。它既不是执行次数,也不是CompileThreshold参数。
CompileThreshold
最佳解释(显然是唯一合理的解释)可以在HotSpot源中找到,请参阅advancedThresholdPolicy.hpp。
我将总结此高级编译策略的要点:
每次计数器达到一定的频率值(TierXInvokeNotifyFreqLog,TierXBackedgeNotifyFreqLog),编译政策被称为决定下一步与当前正在运行的方法做什么。取决于的值i,b而C1和C2的编译器线程的当前负载,可以决定
(TierXInvokeNotifyFreqLog,TierXBackedgeNotifyFreqLog)
继续在解释器中执行;
最后在没有配置文件或计数器的第1层使用C1编译方法(也不可能)。 这里的关键参数是TierXInvocationThreshold和TierXBackEdgeThreshold。可以根据编译队列的长度为给定方法动态调整阈值。
TierXInvocationThreshold
TierXBackEdgeThreshold
编译队列不是FIFO,而是优先级队列。
具有概要数据(第3层)的C1编译代码的行为类似,不同之处在于切换到下一个级别(C2,第4层)的阈值要大得多。例如,大约200次调用后,解释的方法可以在第3层进行编译,而经过5000次调用后,C1编译的方法将在第4层进行重新编译。
特殊策略用于方法内联。即使它们不是“热”的,它们也可以内联到调用方中。只有频繁调用()时InlineFrequencyRatio,才可以内联更大的方法InlineFrequencyCount。
InlineFrequencyRatio
InlineFrequencyCount