Java JIT는 JDK 코드를 실행할 때 부정행위를 합니까?
몇 가지 코드를 벤치마킹하고 있었는데, 같은 알고리즘을 사용해도 와 같은 속도로 실행할 수 없었습니다.그래서 소스를 내 패키지에 복사하고 다음을 시도했습니다.
//import java.math.BigInteger;
public class MultiplyTest {
public static void main(String[] args) {
Random r = new Random(1);
long tm = 0, count = 0,result=0;
for (int i = 0; i < 400000; i++) {
int s1 = 400, s2 = 400;
BigInteger a = new BigInteger(s1 * 8, r), b = new BigInteger(s2 * 8, r);
long tm1 = System.nanoTime();
BigInteger c = a.multiply(b);
if (i > 100000) {
tm += System.nanoTime() - tm1;
count++;
}
result+=c.bitLength();
}
System.out.println((tm / count) + "nsec/mul");
System.out.println(result);
}
}
이것을 실행하면(MacOS에서는 jdk 1.8.0_144-b01) 다음과 같이 출력됩니다.
12089nsec/mul
2559044166
Import 행에 코멘트 없이 실행하는 경우:
4098nsec/mul
2559044166
BigInteger의 JDK 버전을 사용하면 동일한 코드를 사용하더라도 거의 3배 더 빠릅니다.
javap을 사용하여 바이트 코드를 조사하고 옵션과 함께 실행할 때의 컴파일러 출력을 비교했습니다.
-Xbatch -XX:-TieredCompilation -XX:+PrintCompilation -XX:+UnlockDiagnosticVMOptions
-XX:+PrintInlining -XX:CICompilerCount=1
두 버전 모두 동일한 코드를 생성하는 것 같습니다.핫스팟은 코드에 사용할 수 없는 미리 계산된 최적화를 사용하고 있습니까?나는 그들이 그렇지 않다는 것을 항상 이해했다.무엇이 이 차이를 설명합니까?
네, HotSpot JVM은 특별한 버전의 HotSpot JVM이 있기 때문에 일종의 "사기"입니다.BigInteger
Java 코드에서는 찾을 수 없는 메서드입니다.이러한 방법을 JVM 내장이라고 합니다.
특히,BigInteger.multiplyToLen
는 HotSpot의 instrinsic 메서드입니다.JVM 소스 기반에는 x86-64 아키텍처 전용으로 특별한 수동 코드 어셈블리가 구현되어 있습니다.
이 instrinsic을 디세블로 할 수 있습니다.-XX:-UseMultiplyToLenIntrinsic
JVM이 순수 Java 구현을 사용하도록 강제하는 옵션입니다.이 경우 성능은 복사한 코드의 성능과 비슷합니다.
추신: 다음은 다른 HotSpot 고유 메서드 목록입니다.
Java 8 에서는, 이것은 실로 본질적인 메서드입니다.메서드의 약간 변경된 버전입니다.
private static BigInteger test() {
Random r = new Random(1);
BigInteger c = null;
for (int i = 0; i < 400000; i++) {
int s1 = 400, s2 = 400;
BigInteger a = new BigInteger(s1 * 8, r), b = new BigInteger(s2 * 8, r);
c = a.multiply(b);
}
return c;
}
다음을 사용하여 실행:
java -XX:+UnlockDiagnosticVMOptions
-XX:+PrintInlining
-XX:+PrintIntrinsics
-XX:CICompilerCount=2
-XX:+PrintCompilation
<YourClassName>
많은 행이 인쇄됩니다.그 중 하나는 다음과 같습니다.
java.math.BigInteger::multiplyToLen (216 bytes) (intrinsic)
반면 Java 9에서는 이 메서드가 더 이상 본질적인 메서드가 아닌 것처럼 보이지만, 결국 본질적인 메서드를 호출합니다.
@HotSpotIntrinsicCandidate
private static int[] implMultiplyToLen
따라서 Java 9에서 동일한 코드(같은 파라미터)를 실행하면 다음과 같은 결과가 나타납니다.
java.math.BigInteger::implMultiplyToLen (216 bytes) (intrinsic)
그 아래에는 메서드 코드와 이름이 약간 다를 뿐입니다.
언급URL : https://stackoverflow.com/questions/45912510/does-java-jit-cheat-when-running-jdk-code
'IT이야기' 카테고리의 다른 글
C에서 오브젝트 파일을 링크하려면 어떻게 해야 하나요?"아키텍처 x86_64에 대한 정의되지 않은 기호"에서 실패함 (0) | 2022.06.02 |
---|---|
사물의 깊은 복사는 어떻게 합니까? (0) | 2022.06.02 |
'구조나 조합이 아닌 조합원 요청'은 무슨 뜻입니까? (0) | 2022.06.02 |
JPA hashCode() / equals() 딜레마 (0) | 2022.06.02 |
라우터 링크로 vue-multicelect를 채우다 (0) | 2022.06.02 |