There are two logical groups of threads in Java application:
- application threads performing application logic
- threads performing GC
When performing operations such as heap compaction, GC threads move some objects around and those objects cannot be used by any of the application thread, because their physical location may change. This leads to so called stop-the-world pause.
Stop-the-world (STW) pause is when all application threads are stopped. These pauses have one of the biggest impact on Java application performance. The basic concept behind GC tuning is to minimize those pauses. Even though there are some differences between GC algorithms, all of them have stop-the-world pauses during the collection of the young generation (minor GC).
However, application threads cannot be stopped at any time. This is where safepoints come into play. The following definition of safepoint comes from HotSpot glossary:
A point during program execution at which all GC roots are known and all heap object contents are consistent. From a global point of view, all threads must block at a safepoint before the GC can run.
What it basically means is that safepoint is the point in the execution when the JVM is in a state which can be safely viewed and manipulated by other threads (especially by GC threads).
Stop-the-world pauses performed by GC are not the only situations when safepoints are used. They can be also used during code deoptimization, hot swap or when code cache is flushed.
According to Peter Lawrey, there is no special rule where the JVM will place safepoints. It can vary from Java version to version, but some sources available on the internet claim that it happens usually after return from calls or after back jump from loop for JIT-compiled code.
There are couple of flags which can be pretty handy when tracing safepoints:
-XX:+PrintGCApplicationStoppedTime – prints pause time for all safepoints (not only GC ones)
The output will look like this:
Application time: 0.2410613 seconds
Total time for which application threads were stopped: 0.0511005 seconds
The flags above print out the name of the operation that triggered the pause and some additional info (such as number of threads stopped and a timestamp when the event occurred).
All these flags print the information to the standard output, not to the GC log.