2016-12-27 2 views
8

이 코드가 있다고 가정 (정말 내가 생각하지만, 여기 경우에 그것이 중요하지 않습니다) : 여기java9 고유의 방법

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(); 
    } 
} 

그리고 내가 그것을 호출하고 어떻게 (사용 java9) :

내가 알아 내려고하는 것은 내장 된 코드로 대체 된 메서드입니다. (안전하지 않은 내부) 명중 첫 번째 :

 @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가 실제로 내장 호출로 대체 된 경우 다른 모든 내장 메소드를 호출 스택으로 바꾸어야하는 이유가 더 이상 사용되지 않습니다. 메서드 호출 스택이 바닥에서 가로 지르는 것처럼 간단하다고 가정합니다.

+1

아마도 + PrintCompilation (또는 새로운 통합 로깅이 무엇이든지간에)을 추가하고 컨텍스트에서 빛을 비추십시오. – the8472

답변

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.getAndAdd은 사용자의 AtomicJDK9.atomicIncrement보다 조금 더 빨리 호출 임계 값에 도달합니다. 그런 다음 getAndAdd이 컴파일 대기열에 제출되고 첫 번째 내장 프린트 아웃이 제공됩니다.
  • HotSpot JVM은 백그라운드에서 메소드를 컴파일합니다. 메소드가 컴파일되는 동안 인터프리터에서 실행이 계속됩니다.
  • AtomicInteger.getAndAdd이 해석되는 동안에도 Unsafe.getAndAddInt 및 메서드는 호출 임계 값에 도달하여 컴파일을 시작합니다. 이러한 Unsafe 메서드를 컴파일하는 동안 다음 3 개의 내장 함수가 인쇄됩니다.
  • 마지막으로 AtomicJDK9.atomicIncrement도 호출 threashold에 도달하여 컴파일을 시작합니다. 마지막 고유 인쇄물이 해당 방법에 해당합니다.