java - Java 9 中不明确的内在行为

标签 java jvm virtual-machine jvm-arguments java-9

假设我有这段代码(我认为这真的无关紧要,但以防万一):

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.getAndAddIntUnsafe.weakCompareAndSwapIntVolatile 方法也达到调用阈值并开始编译。在编译这些 Unsafe 方法时会打印接下来的 3 个内在函数。
  • 最后,AtomicJDK9.atomicIncrement 也达到调用阈值并开始编译。最后一个内部打印输出对应于您的方法。

关于java - Java 9 中不明确的内在行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41350592/

相关文章:

java - Eclipse:如何取消绑定(bind) Ctlr+I

java - 如何检查图像是否存在于特定位置?

java - 使用 Java 创建 SOAP 服务外观

function - 确保kotlin方法是静态的,顶级的或带注释的@JvmStatic

jvm - Java程序执行背后的内部过程

Azure 故障排除 HTTP 500 : Validate user in memberhsip provider is not called

azure - 为什么尝试从 Ubuntu 22.04 通过 SSH 连接到 Azure Linux 虚拟机时总是超时?

java - Spring Boot Actuator的DataSourcesHealthIndicatorConfiguration找不到dataSource bean

java - 调用内置的 java 本地方法

azure - 无法连接两个 Azure 虚拟机 - 权限被拒绝(公钥)