Let’s consider the following scenario:

  1. When GC is required, you need to know which objects are still in use or are no longer in use and can be recycled, which requires the object usage of each thread.
  2. For Biased locks, to unlock bias at high concurrency, you need exact information about the thread state and the thread that acquired the Lock.
  3. Either just-in-time compile optimization (OSR on-stack replacement) or de-optimization (ubiquitum-stack de-optimization) of a method requires information about where the thread actually runs to the method.

All of these operations require information about the thread, such as what is in the registers, heap usage, stack method code, etc., and the thread needs to pause until the operation is complete, otherwise there will be concurrency problems. That’s where SafePoint comes in.

Safepoint can be understood as special points in code execution where a thread can pause when it executes. SafePoint stores running information about the current thread that is not available elsewhere for other threads to read. This information includes any information about the thread context, such as internal Pointers to objects or non-objects, and so on. We generally understand SafePoint as follows: only when a thread runs to SafePoint, all its state information is determined, and only then can we know which memory the thread uses and which memory it does not use. In addition, only when a thread is in SafePoint position and changes are made to the JVM’s stack information, such as reclaiming unused memory, will the thread be aware of the changes and continue to run. Each thread has a snapshot of its own memory usage and is unaware of the changes made by other threads. It’s only going to be aware when you go to SafePoint again.

Therefore, the GC must require all threads to enter SafePoint at the same time and stay there, waiting for the GC to finish processing memory before letting all threads continue. A case like this where all threads enter SafePoint to wait is Stop the world

Why SafePoint and Stop The World?

The SafePoint location holds anything in the thread context, including objects, internal Pointers to objects or non-objects, and changes to this information while the thread is in SafePoint make it aware of it. So, only if the thread is in SafePoint can GC the memory used by the thread and change the code being executed, such as OSR (On Stack Replacement, Replace existing code on the stack with JIT optimized code) or ubiquitously (replace JIT optimized code on the stack with de-optimized code). Also, there is an important Java threading feature that is implemented based on SafePoint, thread.interrupt (), where a Thread is not known to have been interrupted until it runs to SafePoint.

Why Stop The World? Sometimes we need all threads globally to enter SafePoint in order to count The memory that can still be recycled for GC, and for code that is no longer used to clean up The CodeCache, As well as executing some Java instrument commands or JDK tools such as jStack to print the stack, you need to Stop the world to take snapshots of all current threads.

How is SafePoint implemented?

It can be understood that SafePoint can be inserted into certain positions of the code. When running SafePoint code, each thread actively checks whether it needs to enter SafePoint. This proactive checking process is called Polling

In theory, you could put a Safepoint machine command at the edge of every Java compiled bytecode. At this point, the thread will Polling to ask if the JVM needs to enter SafePoint. This query is performance-costly, so the JIT will optimize to minimize SafePoint.

Jit-compiled code places a SafePoint before the return of all methods and loops (unbounded loops) of any non-counted loop, which can’t be suspended in case GC needs to Stop the world, But for explicitly bounded loops, in order to reduce SafePoint, a SafePoint is not placed before the jump back, i.e. :

for (int i = 0; i < 100000000; i++) {
    ...
}
Copy the code

SafePoint will not be placed inside, which leads to some of the performance tuning issues discussed later. Note that only for int bounded loops, for example int I with long I will still have SafePoint;

SafePoint implementation source code: safepoint.cpp

As you can see, there are five cases of threads for SafePoint; Suppose there is now an operation that triggers a VM thread and all threads need to enter SafePoint (for example now GC is required) if other threads now:

  • Run bytecodeWhen the bytecode is run, the interpreter looks to see if the thread is marked poll armed, and if so, the VM thread callsSafepointSynchronize::block(JavaThread *thread)To carry on the block.
  • Running native code: When running native code, the VM thread skips the thread, but poll Armed the thread so that after executing native code, it checks for poll Armed and blocks if it still needs to stop at SafePoint.
  • Run JIT-compiled code: Since running compiled machine code, directly check whether the local polling page is dirty. If so, block is required. This feature was introduced in Java 10 after JEP 312: Threadlocal Handshakes, where you only need to check if the Local polling page is dirty.
  • In the BLOCK state: Do not leave the BLOCK state until all threads that need to enter SafePoint are completed
  • Thread state or VM running state: polls the thread state until the thread is blocked (the thread must be in any of the four states mentioned above, which will block).