java9内在方法不清楚

时间:2016-12-27 18:50:54

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

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

brew install coreutils
brew install binutils
brew install diffutils
brew install ed --with-default-names
brew install findutils --with-default-names
brew install gawk
brew install gnu-indent --with-default-names
brew install gnu-sed --with-default-names
brew install gnu-tar --with-default-names
brew install gnu-which --with-default-names
brew install gnutls
brew install grep --with-default-names
brew install gzip
brew install screen
brew install watch
brew install wdiff --with-gettext
brew install wget
brew install bash
brew install emacs
brew install gdb
brew install gpatch
brew install less
brew install m4
brew install make
brew install nano
brew install file-formula
brew install git
brew install openssh
brew install perl
brew install python
brew install rsync
brew install svn
brew install unzip
brew install vim --override-system-vi
brew install macvim --override-system-vim --custom-system-icons
brew install zsh

sudo launchctl config user path /usr/local/opt/coreutils/libexec/gnuman:/usr/local/sbin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin:/Library/TeX/texbin

以下是我如何调用它(使用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 -XX:+UnlockDiagnosticVMOptions 
      -XX:-TieredCompilation  
      -XX:+PrintIntrinsics  
      AtomicJDK9

此方法确实存在于上述调用的输出中:

      @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)

为什么 getAndAddInt 在输出中出现两次?

如果getAndAddInt确实被内部调用替换,为什么需要在调用堆栈中替换所有其他内部方法 l它们将不再被使用。我认为这很简单,因为方法调用的堆栈是从底部遍历的。

1 个答案:

答案 0 :(得分:7)

为了说明编译器逻辑,我使用以下参数运行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.getAndAddAtomicJDK9.atomicIncrement早一点达到调用阈值。然后getAndAdd被提交到编译队列,这就是第一个内在打印输出的来源。
  • HotSpot JVM在后台编译方法。在编译方法时,将在解释器中继续执行。
  • 解释AtomicInteger.getAndAdd时,Unsafe.getAndAddIntUnsafe.weakCompareAndSwapIntVolatile方法也会达到调用阈值并开始编译。在编译这些Unsafe方法时会打印下3个内在函数。
  • 最后,AtomicJDK9.atomicIncrement也到达调用threashold并开始编译。最后一个内在打印输出对应于您的方法。