Что вызывает длительное время вращения и синхронизации в 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) изменяется. Я также видел, например. RevokeBias, G1IncCollectionPause или GCG_Operation. Кроме того, page_trap_count кажется несущественным. Я видел примеры, где это было 0, а другие, где это было 2. Согласовано, однако, состоит в том, что время всегда отражается в значениях spin и sync.

Я ищу подробное объяснение этих значений времени spin и sync, но в основном меня интересует, почему это происходит и что я могу сделать против этого. Я не знаю ничего "злого" в нашей конфигурации. На машине много скучных ядер и неиспользуемой памяти, мы используем чистую Java (нет JNI), и нам не известно о чрезмерной синхронизации в нашем коде.

Ответ 1

Проблема заключается в том, что для приложения safepoint требуется много времени. Выход Stopping threads обозначает время, которое требуется между проблемами JVM, для запроса safepoint до тех пор, пока все потоки не достигнут safepoint.

Значение sync показывает то же самое - это время, необходимое для того, чтобы все потоки достигли safeponit.

Значения spin и block обозначают время, необходимое для достижения тем blocked и spinning (исполняемого кода) потоков, чтобы достичь safepoint.

Зная это, мы можем заключить, что проблема для вас в том, что один поток занят вращением и не может достичь своего безопасного места за несколько секунд.

Именно поэтому это трудно сказать. Например, как показано в этом вопросе, и он отвечает, что компилятор JIT может скомпилировать тяжелые циклы без проверок safepoint.

Вы можете попробовать запустить JVM с параметрами -XX:+SafepointTimeout -XX:SafepointTimeoutDelay=500. Это приведет к тайм-ауту синхронизации safepoint через 500 мс и распечатает информацию о потоках, которые не смогли достичь safepoint.