假设我有这段代码(我认为这真的无关紧要,但以防万一):
public class AtomicJDK9 {
static AtomicInteger ai = new AtomicInteger(0);
public static void main(String[] args) {
int sum = 0;
for (int i = 0; i < 30_000; ++i) {
sum += atomicIncrement();
}
System.out.println(sum);
}
public static int atomicIncrement() {
ai.getAndAdd(12);
return ai.get();
}
}
下面是我调用它的方式(使用 java-9):
java -XX:+UnlockDiagnosticVMOptions
-XX:-TieredCompilation
-XX:+PrintIntrinsics
AtomicJDK9
我想找出的是哪些方法被内部代码取代了。第一个被击中的(在 Unsafe 内部):
@HotSpotIntrinsicCandidate
public final int getAndAddInt(Object o, long offset, int delta) {
int v;
do {
v = getIntVolatile(o, offset);
} while (!weakCompareAndSwapIntVolatile(o, offset, v, v + delta));
return v;
}
并且此方法确实存在于上述调用的输出中:
@ 8 jdk.internal.misc.Unsafe::getAndAddInt (27 bytes) (intrinsic)
但是,整个输出很奇怪(对我来说就是这样):
@ 8 jdk.internal.misc.Unsafe::getAndAddInt (27 bytes) (intrinsic)
@ 3 jdk.internal.misc.Unsafe::getIntVolatile (0 bytes) (intrinsic)
@ 18 jdk.internal.misc.Unsafe::weakCompareAndSwapIntVolatile (11 bytes) (intrinsic)
@ 7 jdk.internal.misc.Unsafe::compareAndSwapInt (0 bytes) (intrinsic)
@ 8 jdk.internal.misc.Unsafe::getAndAddInt (27 bytes) (intrinsic)
为什么 getAndAddInt 在输出中出现两次?
此外,如果 getAndAddInt 确实被内部调用所取代,为什么需要替换调用堆栈中的所有其他内部方法l 它们将不再被使用。我假设它就像从底部遍历方法调用堆栈一样简单。
最佳答案
为了说明编译器逻辑,我使用以下参数运行 JVM。
-XX:-TieredCompilation -XX:CICompilerCount=1
-XX:+UnlockDiagnosticVMOptions -XX:+PrintCompilation -XX:+PrintInlining
这就是它打印的内容。
337 29 java.util.concurrent.atomic.AtomicInteger::getAndAdd (12 bytes)
@ 8 jdk.internal.misc.Unsafe::getAndAddInt (27 bytes) (intrinsic)
337 30 jdk.internal.misc.Unsafe::getAndAddInt (27 bytes)
@ 3 jdk.internal.misc.Unsafe::getIntVolatile (0 bytes) (intrinsic)
@ 18 jdk.internal.misc.Unsafe::weakCompareAndSwapIntVolatile (11 bytes) (intrinsic)
338 32 jdk.internal.misc.Unsafe::weakCompareAndSwapIntVolatile (11 bytes)
@ 7 jdk.internal.misc.Unsafe::compareAndSwapInt (0 bytes) (intrinsic)
339 33 AtomicJDK9::atomicIncrement (16 bytes)
@ 5 java.util.concurrent.atomic.AtomicInteger::getAndAdd (12 bytes) inline (hot)
@ 8 jdk.internal.misc.Unsafe::getAndAddInt (27 bytes) (intrinsic)
@ 12 java.util.concurrent.atomic.AtomicInteger::get (5 bytes) accessor
- 方法仅对编译器而言是内在函数,对解释器而言不是。
- 每个方法都在解释器中启动,直到它是considered hot。 .
AtomicInteger.getAndAdd
不仅会从您的代码中调用,还会从普通的 JDK 代码中调用。- 也就是说,
AtomicInteger.getAndAdd
比您的AtomicJDK9.atomicIncrement
早一点达到调用阈值。然后getAndAdd
被提交到编译队列,这就是第一个内部打印输出的来源。 - HotSpot JVM 在后台编译方法。编译方法时,解释器会继续执行。
- 在解释
AtomicInteger.getAndAdd
时,Unsafe.getAndAddInt
和Unsafe.weakCompareAndSwapIntVolatile
方法也达到调用阈值并开始编译。在编译这些Unsafe
方法时会打印接下来的 3 个内在函数。 - 最后,
AtomicJDK9.atomicIncrement
也达到调用阈值并开始编译。最后一个内部打印输出对应于您的方法。
关于java - Java 9 中不明确的内在行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41350592/