When JIT Optimizes Away Safepoint Polls: Causes, Evidence, and Fixes
This article explains how JIT compilation can eliminate safepoint polls in hot loops, causing unexpected thread blocking, and demonstrates how to reproduce, verify, and resolve the issue using JITWatch and JVM options.
This article investigates why a loop that repeatedly calls AtomicInteger.getAndAdd can prevent the main thread from reaching a safepoint, leading to unexpected blocking.
The root cause is JIT optimization: the JIT compiler treats the loop body as hot code, removes the safepoint poll, and thus the thread cannot be stopped at a safepoint.
Because the loop body is identified as hot code, the JIT compilation removes the entry to the safepoint, so the thread cannot enter a safepoint inside the loop.
The original test case is:
public class MainTest {
public static AtomicInteger num = new AtomicInteger(0);
public static void main(String[] args) throws InterruptedException {
Runnable runnable = () -> {
for (int i = 0; i < 1000000000; i++) {
num.getAndAdd(1);
}
System.out.println(Thread.currentThread().getName() + " execution finished!");
};
Thread t1 = new Thread(runnable);
Thread t2 = new Thread(runnable);
t1.start();
t2.start();
Thread.sleep(1000);
System.out.println("num = " + num);
}
}When run with a JDK version higher than 10, the main thread waits for the child threads instead of printing after the sleep.
Changing the loop counter type from int to long or inserting Thread.sleep(0) restores the expected behavior because the loop is no longer treated as a counted hot loop.
Bold Hypothesis
The first guess is to blame the JIT compiler: the hot code num.getAndAdd(1) is optimized away, removing the safepoint.
Hot code in the JVM is defined as either frequently called methods or loops that execute many times.
When such code is compiled, the whole method is compiled, and the entry point (Byte Code Index) may differ, leading to On‑Stack Replacement (OSR) compilation.
Careful Verification
Disabling JIT with -Djava.compiler=NONE shows that the main thread proceeds after the sleep, confirming that the missing safepoint is caused by JIT optimization.
-Djava.compiler=NONE
Using the tool JITWatch you can compare the assembly generated at the C1 and C2 compilation stages. The presence of the {poll} instruction indicates a safepoint; it disappears after full C2 optimization.
Adding Thread.sleep(0) forces the compiler to keep the safepoint poll, preventing the aggressive optimization.
Key Article
The detailed explanation of safepoints can be found in nitsanw’s blog post “The Meaning, Side‑effects and Cost of Safepoints”.
http://psy-lob-saw.blogspot.com/2015/12/safepoints.html
Important sections include:
What is a Safepoint?
When is a thread at a safepoint?
Bringing a Java thread to a safepoint
For C1/C2 compiled code, safepoint polls are inserted at method entry/exit, on non‑counted loop back‑edges, and between bytecodes in interpreter mode.
When a method is inlined, the compiler removes these polls, which explains the observed behavior.
Examples from “牛哥”
Two representative cases are shown:
Example 0 – Long TTSP Hangs Application
public class WhenWillItExit {
public static void main(String[] args) throws InterruptedException {
Thread t = new Thread(() -> {
long l = 0;
for (int i = 0; i < Integer.MAX_VALUE; i++) {
for (int j = 0; j < Integer.MAX_VALUE; j++) {
if ((j & 1) == 1) l++;
}
}
System.out.println("How Odd:" + l);
});
t.setDaemon(true);
t.start();
Thread.sleep(5000);
}
}The thread never stops after 5 seconds because the loop is optimized into a non‑counted hot loop.
Example 4 – Benchmark from Netty
A Netty issue discusses whether to use int or long in tight loops. The benchmark shows negligible difference, but the underlying JIT behavior still matters for safepoint insertion.
In summary, the missing safepoint poll is caused by JIT’s aggressive optimization of counted loops. Disabling JIT, using long counters, or inserting a harmless Thread.sleep(0) are practical ways to keep the safepoint and avoid the unexpected blocking.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Su San Talks Tech
Su San, former staff at several leading tech companies, is a top creator on Juejin and a premium creator on CSDN, and runs the free coding practice site www.susan.net.cn.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
