I've been conducting a stress test using async-profiler to generate a flame graph and happened to notice that, when JDWP is attached, there are frequent cases of deoptimization consuming a significant amount of CPU time.
Here is the flame graph with JDWP attached:
-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005
Here is the flame graph without JDWP attached:

I tried adding the -XX:+PrintCompilation parameter but only observed minimal deoptimization logs.
I also attempted to use JFR (Java Flight Recorder), but I didn't receive any deoptimization events:

This has been quite perplexing for me because when using async-profiler, I can observe a significant amount of CPU time being consumed by deoptimization, but when using JFR, deoptimization seems to disappear.
And by the way, this holds true for both Java 8 and Java 17.
> /Library/Java/JavaVirtualMachines/jdk-1.8.jdk/Contents/Home/bin/java -version
java version "1.8.0_371"
Java(TM) SE Runtime Environment (build 1.8.0_371-b11)
Java HotSpot(TM) 64-Bit Server VM (build 25.371-b11, mixed mode)
> /Library/Java/JavaVirtualMachines/zulu-17.jdk/Contents/Home/bin/java -version
openjdk version "17.0.3" 2022-04-19 LTS
OpenJDK Runtime Environment Zulu17.34+19-CA (build 17.0.3+7-LTS)
OpenJDK 64-Bit Server VM Zulu17.34+19-CA (build 17.0.3+7-LTS, mixed mode, sharing)
Edit:
After looking through the mailing list and JDK bug lists with the keyword deoptimization, I have found two cases reported before that are very similar:
- Deoptimization taking up most CPU cycles
- JDK-8243615: Continuous deoptimizations with Reason=unstable_if and Action=none
Running the code provided by JDK-8243615 without JDWP, I do reproduce the problem:
// javac UnstableIfTest.java
// java -XX:PerMethodRecompilationCutoff=4 UnstableIfTest
public class UnstableIfTest {
static int compute(double x)
{
return (int) (Math.sin(x) + Math.cos(x));
}
static void hotMethod(int iteration)
{
if (iteration < 20) {
compute(78.3);
}
else if (iteration < 40) {
compute(78.3);
}
else if (iteration < 60) {
compute(78.3);
}
else if (iteration < 80) {
compute(78.3);
} else if (iteration < 100) {
compute(78.3);
} else {
compute(78.3);
}
}
static void hotMethodWrapper(int iteration)
{
int count = 100_000;
for (int i = 0; i < count; i++) {
hotMethod(iteration);
}
}
public static void main(String[] args)
{
for (int k = 0; k < 100; k++) {
long start = System.nanoTime();
hotMethodWrapper(k + 1);
System.out.println("iteration " + k + ": " + (System.nanoTime() - start) / 1_000_000 + "ms");
}
}
}
So for now,my guess is this:there is a bug in JIT that causes a lot of unnecessary deoptimization sometimes, but not sure if there' any relation between JDWP, async-profiler, and JFR.

