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

What causes long spin and sync times in 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 的深入解释,但主要是我感兴趣的是为什么会发生这种情况以及我可以采取什么措施来解决它。我不知道我们的配置中有什么 'evil'。机器上有很多无聊的核心和未使用的内存,我们是 运行 纯 Java(没有 JNI),我们没有发现代码中有任何过度同步。

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

sync 值显示相同的东西 - 它是所有线程到达安全点所需的时间。

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

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

很难说为什么会发生这种情况。一个示例,如 this 问题及其答案所示,JIT 编译器可以在没有安全点检查的情况下编译繁重的循环。

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