什么原因导致Java中的长旋转和同步时间?

在Java 8 Update 45中,将这些选项添加到java调用中:

 -XX:+PrintGCApplicationStoppedTime -XX:+PrintSafepointStatistics -XX:PrintSafepointStatisticsCount=1 

向我显示这些统计数据:

 vmop [threads: total initially_running wait_to_block] [time: spin block sync cleanup vmop] page_trap_count 3679.229: no vm operation [ 72 1 2 ] [ 6016 0 6016 0 0 ] 1 2015-05-22T11:25:27.519+0200: Total time for which application threads were stopped: 6.0168551 seconds, Stopping threads took: 6.0164099 seconds 

这里的问题是Stopping threads时间很长。 在这个例子中,它是6秒,这已经是我们的应用程序的一个问题,但我已经看到更大的时间,在一个实例(没有完整的日志记录,但)相当于近一分钟。

VM操作(这里: no vm operation )是变化的。 我也看到过,例如RevokeBiasG1IncCollectionPauseGCG_Operation 。 此外, page_trap_count似乎无关紧要。 我已经看到它为0的示例,以及其它的2的示例。但是,一致的是,时间总是反映在spinsync的值中。

我正在寻找对那些定时值spinsync的深入解释,但大多数情况下我感兴趣的是为什么会发生这种情况以及我能做些什么来反对它。 我不知道我们的配置中有什么“邪恶”。 机器上有很多无聊的内核和未使用的内存,我们运行纯Java(没有JNI),我们不知道代码中有任何过多的同步。

这里的问题是你的应用程序需要很长时间才能达到安全点。 Stopping threads输出表示JVM发出安全点请求到所有线程都达到安全点之间所需的时间。

sync值显示相同的事情 – 它是所有线程到达安全程序所需的时间。

spinblock值表示blockedspinning (执行代码)线程到达安全点所花费的时间。

知道了这一点,我们可以得出结论,问题在于,一个线程正忙于旋转,无法在几秒钟内达到其安全点。

究竟为什么会发生这种情况很难说。 一个例子,如这个问题所示,它的答案是JIT编译器可以编译繁重的循环而无需安全点检查。

您可以尝试使用-XX:+SafepointTimeout -XX:SafepointTimeoutDelay=500选项运行JVM -XX:+SafepointTimeout -XX:SafepointTimeoutDelay=500 。 这将使500 ms后的安全点同步超时,并打印有关未能达到安全点的线程的信息。