Safepoints and stop-the-world pauses

JVM · lesson 22 of 34 · 4 min read

A pause cannot begin until every thread has reached a point where its state can be read.

Open this lesson in the learning hub

Key points

  • A safepoint is a place where a thread has published a consistent view of its stack and registers, so the VM can inspect it.
  • GC pauses, heap dumps, class redefinition, deoptimisation and most jcmd commands all need a global safepoint first.
  • Threads get there by polling: the JIT plants a cheap check at method returns and loop back-edges, and the thread stops there.
  • A long counted int loop may carry no poll at all, so one thread can keep every other thread waiting to start.
  • Time to safepoint is separate from the pause itself, and -Xlog:safepoint prints the two numbers side by side.
  • If pauses look bad but the GC work is small, read the reaching-safepoint time before you touch a single GC flag.

Example

# every stop-the-world pause is two numbers, not one
java -Xlog:safepoint -jar app.jar

# [12.418s][info][safepoint] Safepoint "G1CollectForAllocation", Time since last: 812 ms,
#                            Reaching safepoint: 0.0421 ms, At safepoint: 6.3110 ms
#                                                ^ waiting          ^ the actual GC work

# find the thread that will not poll
java -XX:+SafepointTimeout -XX:SafepointTimeoutDelay=500 -Xlog:safepoint+stats -jar app.jar
# "# SafepointSynchronize::begin: Timeout detected" then names the guilty thread

# JFR records the same thing, as SafepointBegin / SafepointEnd events
jcmd <pid> JFR.start settings=profile duration=30s filename=/tmp/sp.jfr

A pause is the wait for the slowest thread plus the work itself.

This is a reading copy. The full lesson — with the visual explainer, the interactive lab and a Run button for the code — lives in the JVM course, and every lesson in it is listed on the JVM contents page.